Commit d98f8f05188b45168db43df8ddc9feeb0b1cd512
Committed by
Linus Torvalds
1 parent
4f9e87c045
Exists in
master
and in
7 other branches
[PATCH] Notify page fault call chain for sparc64
Overloading of page fault notification with the notify_die() has performance issues(since the only interested components for page fault is kprobes and/or kdb) and hence this patch introduces the new notifier call chain exclusively for page fault notifications their by avoiding notifying unnecessary components in the do_page_fault() code path. Signed-off-by: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Showing 2 changed files with 37 additions and 1 deletions Inline Diff
arch/sparc64/mm/fault.c
1 | /* $Id: fault.c,v 1.59 2002/02/09 19:49:31 davem Exp $ | 1 | /* $Id: fault.c,v 1.59 2002/02/09 19:49:31 davem Exp $ |
2 | * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc. | 2 | * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc. |
3 | * | 3 | * |
4 | * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) | 4 | * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) |
5 | * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) | 5 | * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <asm/head.h> | 8 | #include <asm/head.h> |
9 | 9 | ||
10 | #include <linux/string.h> | 10 | #include <linux/string.h> |
11 | #include <linux/types.h> | 11 | #include <linux/types.h> |
12 | #include <linux/sched.h> | 12 | #include <linux/sched.h> |
13 | #include <linux/ptrace.h> | 13 | #include <linux/ptrace.h> |
14 | #include <linux/mman.h> | 14 | #include <linux/mman.h> |
15 | #include <linux/signal.h> | 15 | #include <linux/signal.h> |
16 | #include <linux/mm.h> | 16 | #include <linux/mm.h> |
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | #include <linux/smp_lock.h> | 18 | #include <linux/smp_lock.h> |
19 | #include <linux/init.h> | 19 | #include <linux/init.h> |
20 | #include <linux/interrupt.h> | 20 | #include <linux/interrupt.h> |
21 | #include <linux/kprobes.h> | 21 | #include <linux/kprobes.h> |
22 | 22 | ||
23 | #include <asm/page.h> | 23 | #include <asm/page.h> |
24 | #include <asm/pgtable.h> | 24 | #include <asm/pgtable.h> |
25 | #include <asm/openprom.h> | 25 | #include <asm/openprom.h> |
26 | #include <asm/oplib.h> | 26 | #include <asm/oplib.h> |
27 | #include <asm/uaccess.h> | 27 | #include <asm/uaccess.h> |
28 | #include <asm/asi.h> | 28 | #include <asm/asi.h> |
29 | #include <asm/lsu.h> | 29 | #include <asm/lsu.h> |
30 | #include <asm/sections.h> | 30 | #include <asm/sections.h> |
31 | #include <asm/kdebug.h> | 31 | #include <asm/kdebug.h> |
32 | #include <asm/mmu_context.h> | 32 | #include <asm/mmu_context.h> |
33 | 33 | ||
34 | #ifdef CONFIG_KPROBES | ||
35 | ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain); | ||
36 | |||
37 | /* Hook to register for page fault notifications */ | ||
38 | int register_page_fault_notifier(struct notifier_block *nb) | ||
39 | { | ||
40 | return atomic_notifier_chain_register(¬ify_page_fault_chain, nb); | ||
41 | } | ||
42 | |||
43 | int unregister_page_fault_notifier(struct notifier_block *nb) | ||
44 | { | ||
45 | return atomic_notifier_chain_unregister(¬ify_page_fault_chain, nb); | ||
46 | } | ||
47 | |||
48 | static inline int notify_page_fault(enum die_val val, const char *str, | ||
49 | struct pt_regs *regs, long err, int trap, int sig) | ||
50 | { | ||
51 | struct die_args args = { | ||
52 | .regs = regs, | ||
53 | .str = str, | ||
54 | .err = err, | ||
55 | .trapnr = trap, | ||
56 | .signr = sig | ||
57 | }; | ||
58 | return atomic_notifier_call_chain(¬ify_page_fault_chain, val, &args); | ||
59 | } | ||
60 | #else | ||
61 | static inline int notify_page_fault(enum die_val val, const char *str, | ||
62 | struct pt_regs *regs, long err, int trap, int sig) | ||
63 | { | ||
64 | return NOTIFY_DONE; | ||
65 | } | ||
66 | #endif | ||
67 | |||
34 | /* | 68 | /* |
35 | * To debug kernel to catch accesses to certain virtual/physical addresses. | 69 | * To debug kernel to catch accesses to certain virtual/physical addresses. |
36 | * Mode = 0 selects physical watchpoints, mode = 1 selects virtual watchpoints. | 70 | * Mode = 0 selects physical watchpoints, mode = 1 selects virtual watchpoints. |
37 | * flags = VM_READ watches memread accesses, flags = VM_WRITE watches memwrite accesses. | 71 | * flags = VM_READ watches memread accesses, flags = VM_WRITE watches memwrite accesses. |
38 | * Caller passes in a 64bit aligned addr, with mask set to the bytes that need to be | 72 | * Caller passes in a 64bit aligned addr, with mask set to the bytes that need to be |
39 | * watched. This is only useful on a single cpu machine for now. After the watchpoint | 73 | * watched. This is only useful on a single cpu machine for now. After the watchpoint |
40 | * is detected, the process causing it will be killed, thus preventing an infinite loop. | 74 | * is detected, the process causing it will be killed, thus preventing an infinite loop. |
41 | */ | 75 | */ |
42 | void set_brkpt(unsigned long addr, unsigned char mask, int flags, int mode) | 76 | void set_brkpt(unsigned long addr, unsigned char mask, int flags, int mode) |
43 | { | 77 | { |
44 | unsigned long lsubits; | 78 | unsigned long lsubits; |
45 | 79 | ||
46 | __asm__ __volatile__("ldxa [%%g0] %1, %0" | 80 | __asm__ __volatile__("ldxa [%%g0] %1, %0" |
47 | : "=r" (lsubits) | 81 | : "=r" (lsubits) |
48 | : "i" (ASI_LSU_CONTROL)); | 82 | : "i" (ASI_LSU_CONTROL)); |
49 | lsubits &= ~(LSU_CONTROL_PM | LSU_CONTROL_VM | | 83 | lsubits &= ~(LSU_CONTROL_PM | LSU_CONTROL_VM | |
50 | LSU_CONTROL_PR | LSU_CONTROL_VR | | 84 | LSU_CONTROL_PR | LSU_CONTROL_VR | |
51 | LSU_CONTROL_PW | LSU_CONTROL_VW); | 85 | LSU_CONTROL_PW | LSU_CONTROL_VW); |
52 | 86 | ||
53 | __asm__ __volatile__("stxa %0, [%1] %2\n\t" | 87 | __asm__ __volatile__("stxa %0, [%1] %2\n\t" |
54 | "membar #Sync" | 88 | "membar #Sync" |
55 | : /* no outputs */ | 89 | : /* no outputs */ |
56 | : "r" (addr), "r" (mode ? VIRT_WATCHPOINT : PHYS_WATCHPOINT), | 90 | : "r" (addr), "r" (mode ? VIRT_WATCHPOINT : PHYS_WATCHPOINT), |
57 | "i" (ASI_DMMU)); | 91 | "i" (ASI_DMMU)); |
58 | 92 | ||
59 | lsubits |= ((unsigned long)mask << (mode ? 25 : 33)); | 93 | lsubits |= ((unsigned long)mask << (mode ? 25 : 33)); |
60 | if (flags & VM_READ) | 94 | if (flags & VM_READ) |
61 | lsubits |= (mode ? LSU_CONTROL_VR : LSU_CONTROL_PR); | 95 | lsubits |= (mode ? LSU_CONTROL_VR : LSU_CONTROL_PR); |
62 | if (flags & VM_WRITE) | 96 | if (flags & VM_WRITE) |
63 | lsubits |= (mode ? LSU_CONTROL_VW : LSU_CONTROL_PW); | 97 | lsubits |= (mode ? LSU_CONTROL_VW : LSU_CONTROL_PW); |
64 | __asm__ __volatile__("stxa %0, [%%g0] %1\n\t" | 98 | __asm__ __volatile__("stxa %0, [%%g0] %1\n\t" |
65 | "membar #Sync" | 99 | "membar #Sync" |
66 | : /* no outputs */ | 100 | : /* no outputs */ |
67 | : "r" (lsubits), "i" (ASI_LSU_CONTROL) | 101 | : "r" (lsubits), "i" (ASI_LSU_CONTROL) |
68 | : "memory"); | 102 | : "memory"); |
69 | } | 103 | } |
70 | 104 | ||
71 | static void __kprobes unhandled_fault(unsigned long address, | 105 | static void __kprobes unhandled_fault(unsigned long address, |
72 | struct task_struct *tsk, | 106 | struct task_struct *tsk, |
73 | struct pt_regs *regs) | 107 | struct pt_regs *regs) |
74 | { | 108 | { |
75 | if ((unsigned long) address < PAGE_SIZE) { | 109 | if ((unsigned long) address < PAGE_SIZE) { |
76 | printk(KERN_ALERT "Unable to handle kernel NULL " | 110 | printk(KERN_ALERT "Unable to handle kernel NULL " |
77 | "pointer dereference\n"); | 111 | "pointer dereference\n"); |
78 | } else { | 112 | } else { |
79 | printk(KERN_ALERT "Unable to handle kernel paging request " | 113 | printk(KERN_ALERT "Unable to handle kernel paging request " |
80 | "at virtual address %016lx\n", (unsigned long)address); | 114 | "at virtual address %016lx\n", (unsigned long)address); |
81 | } | 115 | } |
82 | printk(KERN_ALERT "tsk->{mm,active_mm}->context = %016lx\n", | 116 | printk(KERN_ALERT "tsk->{mm,active_mm}->context = %016lx\n", |
83 | (tsk->mm ? | 117 | (tsk->mm ? |
84 | CTX_HWBITS(tsk->mm->context) : | 118 | CTX_HWBITS(tsk->mm->context) : |
85 | CTX_HWBITS(tsk->active_mm->context))); | 119 | CTX_HWBITS(tsk->active_mm->context))); |
86 | printk(KERN_ALERT "tsk->{mm,active_mm}->pgd = %016lx\n", | 120 | printk(KERN_ALERT "tsk->{mm,active_mm}->pgd = %016lx\n", |
87 | (tsk->mm ? (unsigned long) tsk->mm->pgd : | 121 | (tsk->mm ? (unsigned long) tsk->mm->pgd : |
88 | (unsigned long) tsk->active_mm->pgd)); | 122 | (unsigned long) tsk->active_mm->pgd)); |
89 | if (notify_die(DIE_GPF, "general protection fault", regs, | 123 | if (notify_die(DIE_GPF, "general protection fault", regs, |
90 | 0, 0, SIGSEGV) == NOTIFY_STOP) | 124 | 0, 0, SIGSEGV) == NOTIFY_STOP) |
91 | return; | 125 | return; |
92 | die_if_kernel("Oops", regs); | 126 | die_if_kernel("Oops", regs); |
93 | } | 127 | } |
94 | 128 | ||
95 | static void bad_kernel_pc(struct pt_regs *regs, unsigned long vaddr) | 129 | static void bad_kernel_pc(struct pt_regs *regs, unsigned long vaddr) |
96 | { | 130 | { |
97 | unsigned long *ksp; | 131 | unsigned long *ksp; |
98 | 132 | ||
99 | printk(KERN_CRIT "OOPS: Bogus kernel PC [%016lx] in fault handler\n", | 133 | printk(KERN_CRIT "OOPS: Bogus kernel PC [%016lx] in fault handler\n", |
100 | regs->tpc); | 134 | regs->tpc); |
101 | printk(KERN_CRIT "OOPS: Fault was to vaddr[%lx]\n", vaddr); | 135 | printk(KERN_CRIT "OOPS: Fault was to vaddr[%lx]\n", vaddr); |
102 | __asm__("mov %%sp, %0" : "=r" (ksp)); | 136 | __asm__("mov %%sp, %0" : "=r" (ksp)); |
103 | show_stack(current, ksp); | 137 | show_stack(current, ksp); |
104 | unhandled_fault(regs->tpc, current, regs); | 138 | unhandled_fault(regs->tpc, current, regs); |
105 | } | 139 | } |
106 | 140 | ||
107 | /* | 141 | /* |
108 | * We now make sure that mmap_sem is held in all paths that call | 142 | * We now make sure that mmap_sem is held in all paths that call |
109 | * this. Additionally, to prevent kswapd from ripping ptes from | 143 | * this. Additionally, to prevent kswapd from ripping ptes from |
110 | * under us, raise interrupts around the time that we look at the | 144 | * under us, raise interrupts around the time that we look at the |
111 | * pte, kswapd will have to wait to get his smp ipi response from | 145 | * pte, kswapd will have to wait to get his smp ipi response from |
112 | * us. vmtruncate likewise. This saves us having to get pte lock. | 146 | * us. vmtruncate likewise. This saves us having to get pte lock. |
113 | */ | 147 | */ |
114 | static unsigned int get_user_insn(unsigned long tpc) | 148 | static unsigned int get_user_insn(unsigned long tpc) |
115 | { | 149 | { |
116 | pgd_t *pgdp = pgd_offset(current->mm, tpc); | 150 | pgd_t *pgdp = pgd_offset(current->mm, tpc); |
117 | pud_t *pudp; | 151 | pud_t *pudp; |
118 | pmd_t *pmdp; | 152 | pmd_t *pmdp; |
119 | pte_t *ptep, pte; | 153 | pte_t *ptep, pte; |
120 | unsigned long pa; | 154 | unsigned long pa; |
121 | u32 insn = 0; | 155 | u32 insn = 0; |
122 | unsigned long pstate; | 156 | unsigned long pstate; |
123 | 157 | ||
124 | if (pgd_none(*pgdp)) | 158 | if (pgd_none(*pgdp)) |
125 | goto outret; | 159 | goto outret; |
126 | pudp = pud_offset(pgdp, tpc); | 160 | pudp = pud_offset(pgdp, tpc); |
127 | if (pud_none(*pudp)) | 161 | if (pud_none(*pudp)) |
128 | goto outret; | 162 | goto outret; |
129 | pmdp = pmd_offset(pudp, tpc); | 163 | pmdp = pmd_offset(pudp, tpc); |
130 | if (pmd_none(*pmdp)) | 164 | if (pmd_none(*pmdp)) |
131 | goto outret; | 165 | goto outret; |
132 | 166 | ||
133 | /* This disables preemption for us as well. */ | 167 | /* This disables preemption for us as well. */ |
134 | __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate)); | 168 | __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate)); |
135 | __asm__ __volatile__("wrpr %0, %1, %%pstate" | 169 | __asm__ __volatile__("wrpr %0, %1, %%pstate" |
136 | : : "r" (pstate), "i" (PSTATE_IE)); | 170 | : : "r" (pstate), "i" (PSTATE_IE)); |
137 | ptep = pte_offset_map(pmdp, tpc); | 171 | ptep = pte_offset_map(pmdp, tpc); |
138 | pte = *ptep; | 172 | pte = *ptep; |
139 | if (!pte_present(pte)) | 173 | if (!pte_present(pte)) |
140 | goto out; | 174 | goto out; |
141 | 175 | ||
142 | pa = (pte_pfn(pte) << PAGE_SHIFT); | 176 | pa = (pte_pfn(pte) << PAGE_SHIFT); |
143 | pa += (tpc & ~PAGE_MASK); | 177 | pa += (tpc & ~PAGE_MASK); |
144 | 178 | ||
145 | /* Use phys bypass so we don't pollute dtlb/dcache. */ | 179 | /* Use phys bypass so we don't pollute dtlb/dcache. */ |
146 | __asm__ __volatile__("lduwa [%1] %2, %0" | 180 | __asm__ __volatile__("lduwa [%1] %2, %0" |
147 | : "=r" (insn) | 181 | : "=r" (insn) |
148 | : "r" (pa), "i" (ASI_PHYS_USE_EC)); | 182 | : "r" (pa), "i" (ASI_PHYS_USE_EC)); |
149 | 183 | ||
150 | out: | 184 | out: |
151 | pte_unmap(ptep); | 185 | pte_unmap(ptep); |
152 | __asm__ __volatile__("wrpr %0, 0x0, %%pstate" : : "r" (pstate)); | 186 | __asm__ __volatile__("wrpr %0, 0x0, %%pstate" : : "r" (pstate)); |
153 | outret: | 187 | outret: |
154 | return insn; | 188 | return insn; |
155 | } | 189 | } |
156 | 190 | ||
157 | extern unsigned long compute_effective_address(struct pt_regs *, unsigned int, unsigned int); | 191 | extern unsigned long compute_effective_address(struct pt_regs *, unsigned int, unsigned int); |
158 | 192 | ||
159 | static void do_fault_siginfo(int code, int sig, struct pt_regs *regs, | 193 | static void do_fault_siginfo(int code, int sig, struct pt_regs *regs, |
160 | unsigned int insn, int fault_code) | 194 | unsigned int insn, int fault_code) |
161 | { | 195 | { |
162 | siginfo_t info; | 196 | siginfo_t info; |
163 | 197 | ||
164 | info.si_code = code; | 198 | info.si_code = code; |
165 | info.si_signo = sig; | 199 | info.si_signo = sig; |
166 | info.si_errno = 0; | 200 | info.si_errno = 0; |
167 | if (fault_code & FAULT_CODE_ITLB) | 201 | if (fault_code & FAULT_CODE_ITLB) |
168 | info.si_addr = (void __user *) regs->tpc; | 202 | info.si_addr = (void __user *) regs->tpc; |
169 | else | 203 | else |
170 | info.si_addr = (void __user *) | 204 | info.si_addr = (void __user *) |
171 | compute_effective_address(regs, insn, 0); | 205 | compute_effective_address(regs, insn, 0); |
172 | info.si_trapno = 0; | 206 | info.si_trapno = 0; |
173 | force_sig_info(sig, &info, current); | 207 | force_sig_info(sig, &info, current); |
174 | } | 208 | } |
175 | 209 | ||
176 | extern int handle_ldf_stq(u32, struct pt_regs *); | 210 | extern int handle_ldf_stq(u32, struct pt_regs *); |
177 | extern int handle_ld_nf(u32, struct pt_regs *); | 211 | extern int handle_ld_nf(u32, struct pt_regs *); |
178 | 212 | ||
179 | static unsigned int get_fault_insn(struct pt_regs *regs, unsigned int insn) | 213 | static unsigned int get_fault_insn(struct pt_regs *regs, unsigned int insn) |
180 | { | 214 | { |
181 | if (!insn) { | 215 | if (!insn) { |
182 | if (!regs->tpc || (regs->tpc & 0x3)) | 216 | if (!regs->tpc || (regs->tpc & 0x3)) |
183 | return 0; | 217 | return 0; |
184 | if (regs->tstate & TSTATE_PRIV) { | 218 | if (regs->tstate & TSTATE_PRIV) { |
185 | insn = *(unsigned int *) regs->tpc; | 219 | insn = *(unsigned int *) regs->tpc; |
186 | } else { | 220 | } else { |
187 | insn = get_user_insn(regs->tpc); | 221 | insn = get_user_insn(regs->tpc); |
188 | } | 222 | } |
189 | } | 223 | } |
190 | return insn; | 224 | return insn; |
191 | } | 225 | } |
192 | 226 | ||
193 | static void do_kernel_fault(struct pt_regs *regs, int si_code, int fault_code, | 227 | static void do_kernel_fault(struct pt_regs *regs, int si_code, int fault_code, |
194 | unsigned int insn, unsigned long address) | 228 | unsigned int insn, unsigned long address) |
195 | { | 229 | { |
196 | unsigned char asi = ASI_P; | 230 | unsigned char asi = ASI_P; |
197 | 231 | ||
198 | if ((!insn) && (regs->tstate & TSTATE_PRIV)) | 232 | if ((!insn) && (regs->tstate & TSTATE_PRIV)) |
199 | goto cannot_handle; | 233 | goto cannot_handle; |
200 | 234 | ||
201 | /* If user insn could be read (thus insn is zero), that | 235 | /* If user insn could be read (thus insn is zero), that |
202 | * is fine. We will just gun down the process with a signal | 236 | * is fine. We will just gun down the process with a signal |
203 | * in that case. | 237 | * in that case. |
204 | */ | 238 | */ |
205 | 239 | ||
206 | if (!(fault_code & (FAULT_CODE_WRITE|FAULT_CODE_ITLB)) && | 240 | if (!(fault_code & (FAULT_CODE_WRITE|FAULT_CODE_ITLB)) && |
207 | (insn & 0xc0800000) == 0xc0800000) { | 241 | (insn & 0xc0800000) == 0xc0800000) { |
208 | if (insn & 0x2000) | 242 | if (insn & 0x2000) |
209 | asi = (regs->tstate >> 24); | 243 | asi = (regs->tstate >> 24); |
210 | else | 244 | else |
211 | asi = (insn >> 5); | 245 | asi = (insn >> 5); |
212 | if ((asi & 0xf2) == 0x82) { | 246 | if ((asi & 0xf2) == 0x82) { |
213 | if (insn & 0x1000000) { | 247 | if (insn & 0x1000000) { |
214 | handle_ldf_stq(insn, regs); | 248 | handle_ldf_stq(insn, regs); |
215 | } else { | 249 | } else { |
216 | /* This was a non-faulting load. Just clear the | 250 | /* This was a non-faulting load. Just clear the |
217 | * destination register(s) and continue with the next | 251 | * destination register(s) and continue with the next |
218 | * instruction. -jj | 252 | * instruction. -jj |
219 | */ | 253 | */ |
220 | handle_ld_nf(insn, regs); | 254 | handle_ld_nf(insn, regs); |
221 | } | 255 | } |
222 | return; | 256 | return; |
223 | } | 257 | } |
224 | } | 258 | } |
225 | 259 | ||
226 | /* Is this in ex_table? */ | 260 | /* Is this in ex_table? */ |
227 | if (regs->tstate & TSTATE_PRIV) { | 261 | if (regs->tstate & TSTATE_PRIV) { |
228 | const struct exception_table_entry *entry; | 262 | const struct exception_table_entry *entry; |
229 | 263 | ||
230 | if (asi == ASI_P && (insn & 0xc0800000) == 0xc0800000) { | 264 | if (asi == ASI_P && (insn & 0xc0800000) == 0xc0800000) { |
231 | if (insn & 0x2000) | 265 | if (insn & 0x2000) |
232 | asi = (regs->tstate >> 24); | 266 | asi = (regs->tstate >> 24); |
233 | else | 267 | else |
234 | asi = (insn >> 5); | 268 | asi = (insn >> 5); |
235 | } | 269 | } |
236 | 270 | ||
237 | /* Look in asi.h: All _S asis have LS bit set */ | 271 | /* Look in asi.h: All _S asis have LS bit set */ |
238 | if ((asi & 0x1) && | 272 | if ((asi & 0x1) && |
239 | (entry = search_exception_tables(regs->tpc))) { | 273 | (entry = search_exception_tables(regs->tpc))) { |
240 | regs->tpc = entry->fixup; | 274 | regs->tpc = entry->fixup; |
241 | regs->tnpc = regs->tpc + 4; | 275 | regs->tnpc = regs->tpc + 4; |
242 | return; | 276 | return; |
243 | } | 277 | } |
244 | } else { | 278 | } else { |
245 | /* The si_code was set to make clear whether | 279 | /* The si_code was set to make clear whether |
246 | * this was a SEGV_MAPERR or SEGV_ACCERR fault. | 280 | * this was a SEGV_MAPERR or SEGV_ACCERR fault. |
247 | */ | 281 | */ |
248 | do_fault_siginfo(si_code, SIGSEGV, regs, insn, fault_code); | 282 | do_fault_siginfo(si_code, SIGSEGV, regs, insn, fault_code); |
249 | return; | 283 | return; |
250 | } | 284 | } |
251 | 285 | ||
252 | cannot_handle: | 286 | cannot_handle: |
253 | unhandled_fault (address, current, regs); | 287 | unhandled_fault (address, current, regs); |
254 | } | 288 | } |
255 | 289 | ||
256 | asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs) | 290 | asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs) |
257 | { | 291 | { |
258 | struct mm_struct *mm = current->mm; | 292 | struct mm_struct *mm = current->mm; |
259 | struct vm_area_struct *vma; | 293 | struct vm_area_struct *vma; |
260 | unsigned int insn = 0; | 294 | unsigned int insn = 0; |
261 | int si_code, fault_code; | 295 | int si_code, fault_code; |
262 | unsigned long address, mm_rss; | 296 | unsigned long address, mm_rss; |
263 | 297 | ||
264 | fault_code = get_thread_fault_code(); | 298 | fault_code = get_thread_fault_code(); |
265 | 299 | ||
266 | if (notify_die(DIE_PAGE_FAULT, "page_fault", regs, | 300 | if (notify_page_fault(DIE_PAGE_FAULT, "page_fault", regs, |
267 | fault_code, 0, SIGSEGV) == NOTIFY_STOP) | 301 | fault_code, 0, SIGSEGV) == NOTIFY_STOP) |
268 | return; | 302 | return; |
269 | 303 | ||
270 | si_code = SEGV_MAPERR; | 304 | si_code = SEGV_MAPERR; |
271 | address = current_thread_info()->fault_address; | 305 | address = current_thread_info()->fault_address; |
272 | 306 | ||
273 | if ((fault_code & FAULT_CODE_ITLB) && | 307 | if ((fault_code & FAULT_CODE_ITLB) && |
274 | (fault_code & FAULT_CODE_DTLB)) | 308 | (fault_code & FAULT_CODE_DTLB)) |
275 | BUG(); | 309 | BUG(); |
276 | 310 | ||
277 | if (regs->tstate & TSTATE_PRIV) { | 311 | if (regs->tstate & TSTATE_PRIV) { |
278 | unsigned long tpc = regs->tpc; | 312 | unsigned long tpc = regs->tpc; |
279 | 313 | ||
280 | /* Sanity check the PC. */ | 314 | /* Sanity check the PC. */ |
281 | if ((tpc >= KERNBASE && tpc < (unsigned long) _etext) || | 315 | if ((tpc >= KERNBASE && tpc < (unsigned long) _etext) || |
282 | (tpc >= MODULES_VADDR && tpc < MODULES_END)) { | 316 | (tpc >= MODULES_VADDR && tpc < MODULES_END)) { |
283 | /* Valid, no problems... */ | 317 | /* Valid, no problems... */ |
284 | } else { | 318 | } else { |
285 | bad_kernel_pc(regs, address); | 319 | bad_kernel_pc(regs, address); |
286 | return; | 320 | return; |
287 | } | 321 | } |
288 | } | 322 | } |
289 | 323 | ||
290 | /* | 324 | /* |
291 | * If we're in an interrupt or have no user | 325 | * If we're in an interrupt or have no user |
292 | * context, we must not take the fault.. | 326 | * context, we must not take the fault.. |
293 | */ | 327 | */ |
294 | if (in_atomic() || !mm) | 328 | if (in_atomic() || !mm) |
295 | goto intr_or_no_mm; | 329 | goto intr_or_no_mm; |
296 | 330 | ||
297 | if (test_thread_flag(TIF_32BIT)) { | 331 | if (test_thread_flag(TIF_32BIT)) { |
298 | if (!(regs->tstate & TSTATE_PRIV)) | 332 | if (!(regs->tstate & TSTATE_PRIV)) |
299 | regs->tpc &= 0xffffffff; | 333 | regs->tpc &= 0xffffffff; |
300 | address &= 0xffffffff; | 334 | address &= 0xffffffff; |
301 | } | 335 | } |
302 | 336 | ||
303 | if (!down_read_trylock(&mm->mmap_sem)) { | 337 | if (!down_read_trylock(&mm->mmap_sem)) { |
304 | if ((regs->tstate & TSTATE_PRIV) && | 338 | if ((regs->tstate & TSTATE_PRIV) && |
305 | !search_exception_tables(regs->tpc)) { | 339 | !search_exception_tables(regs->tpc)) { |
306 | insn = get_fault_insn(regs, insn); | 340 | insn = get_fault_insn(regs, insn); |
307 | goto handle_kernel_fault; | 341 | goto handle_kernel_fault; |
308 | } | 342 | } |
309 | down_read(&mm->mmap_sem); | 343 | down_read(&mm->mmap_sem); |
310 | } | 344 | } |
311 | 345 | ||
312 | vma = find_vma(mm, address); | 346 | vma = find_vma(mm, address); |
313 | if (!vma) | 347 | if (!vma) |
314 | goto bad_area; | 348 | goto bad_area; |
315 | 349 | ||
316 | /* Pure DTLB misses do not tell us whether the fault causing | 350 | /* Pure DTLB misses do not tell us whether the fault causing |
317 | * load/store/atomic was a write or not, it only says that there | 351 | * load/store/atomic was a write or not, it only says that there |
318 | * was no match. So in such a case we (carefully) read the | 352 | * was no match. So in such a case we (carefully) read the |
319 | * instruction to try and figure this out. It's an optimization | 353 | * instruction to try and figure this out. It's an optimization |
320 | * so it's ok if we can't do this. | 354 | * so it's ok if we can't do this. |
321 | * | 355 | * |
322 | * Special hack, window spill/fill knows the exact fault type. | 356 | * Special hack, window spill/fill knows the exact fault type. |
323 | */ | 357 | */ |
324 | if (((fault_code & | 358 | if (((fault_code & |
325 | (FAULT_CODE_DTLB | FAULT_CODE_WRITE | FAULT_CODE_WINFIXUP)) == FAULT_CODE_DTLB) && | 359 | (FAULT_CODE_DTLB | FAULT_CODE_WRITE | FAULT_CODE_WINFIXUP)) == FAULT_CODE_DTLB) && |
326 | (vma->vm_flags & VM_WRITE) != 0) { | 360 | (vma->vm_flags & VM_WRITE) != 0) { |
327 | insn = get_fault_insn(regs, 0); | 361 | insn = get_fault_insn(regs, 0); |
328 | if (!insn) | 362 | if (!insn) |
329 | goto continue_fault; | 363 | goto continue_fault; |
330 | /* All loads, stores and atomics have bits 30 and 31 both set | 364 | /* All loads, stores and atomics have bits 30 and 31 both set |
331 | * in the instruction. Bit 21 is set in all stores, but we | 365 | * in the instruction. Bit 21 is set in all stores, but we |
332 | * have to avoid prefetches which also have bit 21 set. | 366 | * have to avoid prefetches which also have bit 21 set. |
333 | */ | 367 | */ |
334 | if ((insn & 0xc0200000) == 0xc0200000 && | 368 | if ((insn & 0xc0200000) == 0xc0200000 && |
335 | (insn & 0x01780000) != 0x01680000) { | 369 | (insn & 0x01780000) != 0x01680000) { |
336 | /* Don't bother updating thread struct value, | 370 | /* Don't bother updating thread struct value, |
337 | * because update_mmu_cache only cares which tlb | 371 | * because update_mmu_cache only cares which tlb |
338 | * the access came from. | 372 | * the access came from. |
339 | */ | 373 | */ |
340 | fault_code |= FAULT_CODE_WRITE; | 374 | fault_code |= FAULT_CODE_WRITE; |
341 | } | 375 | } |
342 | } | 376 | } |
343 | continue_fault: | 377 | continue_fault: |
344 | 378 | ||
345 | if (vma->vm_start <= address) | 379 | if (vma->vm_start <= address) |
346 | goto good_area; | 380 | goto good_area; |
347 | if (!(vma->vm_flags & VM_GROWSDOWN)) | 381 | if (!(vma->vm_flags & VM_GROWSDOWN)) |
348 | goto bad_area; | 382 | goto bad_area; |
349 | if (!(fault_code & FAULT_CODE_WRITE)) { | 383 | if (!(fault_code & FAULT_CODE_WRITE)) { |
350 | /* Non-faulting loads shouldn't expand stack. */ | 384 | /* Non-faulting loads shouldn't expand stack. */ |
351 | insn = get_fault_insn(regs, insn); | 385 | insn = get_fault_insn(regs, insn); |
352 | if ((insn & 0xc0800000) == 0xc0800000) { | 386 | if ((insn & 0xc0800000) == 0xc0800000) { |
353 | unsigned char asi; | 387 | unsigned char asi; |
354 | 388 | ||
355 | if (insn & 0x2000) | 389 | if (insn & 0x2000) |
356 | asi = (regs->tstate >> 24); | 390 | asi = (regs->tstate >> 24); |
357 | else | 391 | else |
358 | asi = (insn >> 5); | 392 | asi = (insn >> 5); |
359 | if ((asi & 0xf2) == 0x82) | 393 | if ((asi & 0xf2) == 0x82) |
360 | goto bad_area; | 394 | goto bad_area; |
361 | } | 395 | } |
362 | } | 396 | } |
363 | if (expand_stack(vma, address)) | 397 | if (expand_stack(vma, address)) |
364 | goto bad_area; | 398 | goto bad_area; |
365 | /* | 399 | /* |
366 | * Ok, we have a good vm_area for this memory access, so | 400 | * Ok, we have a good vm_area for this memory access, so |
367 | * we can handle it.. | 401 | * we can handle it.. |
368 | */ | 402 | */ |
369 | good_area: | 403 | good_area: |
370 | si_code = SEGV_ACCERR; | 404 | si_code = SEGV_ACCERR; |
371 | 405 | ||
372 | /* If we took a ITLB miss on a non-executable page, catch | 406 | /* If we took a ITLB miss on a non-executable page, catch |
373 | * that here. | 407 | * that here. |
374 | */ | 408 | */ |
375 | if ((fault_code & FAULT_CODE_ITLB) && !(vma->vm_flags & VM_EXEC)) { | 409 | if ((fault_code & FAULT_CODE_ITLB) && !(vma->vm_flags & VM_EXEC)) { |
376 | BUG_ON(address != regs->tpc); | 410 | BUG_ON(address != regs->tpc); |
377 | BUG_ON(regs->tstate & TSTATE_PRIV); | 411 | BUG_ON(regs->tstate & TSTATE_PRIV); |
378 | goto bad_area; | 412 | goto bad_area; |
379 | } | 413 | } |
380 | 414 | ||
381 | if (fault_code & FAULT_CODE_WRITE) { | 415 | if (fault_code & FAULT_CODE_WRITE) { |
382 | if (!(vma->vm_flags & VM_WRITE)) | 416 | if (!(vma->vm_flags & VM_WRITE)) |
383 | goto bad_area; | 417 | goto bad_area; |
384 | 418 | ||
385 | /* Spitfire has an icache which does not snoop | 419 | /* Spitfire has an icache which does not snoop |
386 | * processor stores. Later processors do... | 420 | * processor stores. Later processors do... |
387 | */ | 421 | */ |
388 | if (tlb_type == spitfire && | 422 | if (tlb_type == spitfire && |
389 | (vma->vm_flags & VM_EXEC) != 0 && | 423 | (vma->vm_flags & VM_EXEC) != 0 && |
390 | vma->vm_file != NULL) | 424 | vma->vm_file != NULL) |
391 | set_thread_fault_code(fault_code | | 425 | set_thread_fault_code(fault_code | |
392 | FAULT_CODE_BLKCOMMIT); | 426 | FAULT_CODE_BLKCOMMIT); |
393 | } else { | 427 | } else { |
394 | /* Allow reads even for write-only mappings */ | 428 | /* Allow reads even for write-only mappings */ |
395 | if (!(vma->vm_flags & (VM_READ | VM_EXEC))) | 429 | if (!(vma->vm_flags & (VM_READ | VM_EXEC))) |
396 | goto bad_area; | 430 | goto bad_area; |
397 | } | 431 | } |
398 | 432 | ||
399 | switch (handle_mm_fault(mm, vma, address, (fault_code & FAULT_CODE_WRITE))) { | 433 | switch (handle_mm_fault(mm, vma, address, (fault_code & FAULT_CODE_WRITE))) { |
400 | case VM_FAULT_MINOR: | 434 | case VM_FAULT_MINOR: |
401 | current->min_flt++; | 435 | current->min_flt++; |
402 | break; | 436 | break; |
403 | case VM_FAULT_MAJOR: | 437 | case VM_FAULT_MAJOR: |
404 | current->maj_flt++; | 438 | current->maj_flt++; |
405 | break; | 439 | break; |
406 | case VM_FAULT_SIGBUS: | 440 | case VM_FAULT_SIGBUS: |
407 | goto do_sigbus; | 441 | goto do_sigbus; |
408 | case VM_FAULT_OOM: | 442 | case VM_FAULT_OOM: |
409 | goto out_of_memory; | 443 | goto out_of_memory; |
410 | default: | 444 | default: |
411 | BUG(); | 445 | BUG(); |
412 | } | 446 | } |
413 | 447 | ||
414 | up_read(&mm->mmap_sem); | 448 | up_read(&mm->mmap_sem); |
415 | 449 | ||
416 | mm_rss = get_mm_rss(mm); | 450 | mm_rss = get_mm_rss(mm); |
417 | #ifdef CONFIG_HUGETLB_PAGE | 451 | #ifdef CONFIG_HUGETLB_PAGE |
418 | mm_rss -= (mm->context.huge_pte_count * (HPAGE_SIZE / PAGE_SIZE)); | 452 | mm_rss -= (mm->context.huge_pte_count * (HPAGE_SIZE / PAGE_SIZE)); |
419 | #endif | 453 | #endif |
420 | if (unlikely(mm_rss > | 454 | if (unlikely(mm_rss > |
421 | mm->context.tsb_block[MM_TSB_BASE].tsb_rss_limit)) | 455 | mm->context.tsb_block[MM_TSB_BASE].tsb_rss_limit)) |
422 | tsb_grow(mm, MM_TSB_BASE, mm_rss); | 456 | tsb_grow(mm, MM_TSB_BASE, mm_rss); |
423 | #ifdef CONFIG_HUGETLB_PAGE | 457 | #ifdef CONFIG_HUGETLB_PAGE |
424 | mm_rss = mm->context.huge_pte_count; | 458 | mm_rss = mm->context.huge_pte_count; |
425 | if (unlikely(mm_rss > | 459 | if (unlikely(mm_rss > |
426 | mm->context.tsb_block[MM_TSB_HUGE].tsb_rss_limit)) | 460 | mm->context.tsb_block[MM_TSB_HUGE].tsb_rss_limit)) |
427 | tsb_grow(mm, MM_TSB_HUGE, mm_rss); | 461 | tsb_grow(mm, MM_TSB_HUGE, mm_rss); |
428 | #endif | 462 | #endif |
429 | return; | 463 | return; |
430 | 464 | ||
431 | /* | 465 | /* |
432 | * Something tried to access memory that isn't in our memory map.. | 466 | * Something tried to access memory that isn't in our memory map.. |
433 | * Fix it, but check if it's kernel or user first.. | 467 | * Fix it, but check if it's kernel or user first.. |
434 | */ | 468 | */ |
435 | bad_area: | 469 | bad_area: |
436 | insn = get_fault_insn(regs, insn); | 470 | insn = get_fault_insn(regs, insn); |
437 | up_read(&mm->mmap_sem); | 471 | up_read(&mm->mmap_sem); |
438 | 472 | ||
439 | handle_kernel_fault: | 473 | handle_kernel_fault: |
440 | do_kernel_fault(regs, si_code, fault_code, insn, address); | 474 | do_kernel_fault(regs, si_code, fault_code, insn, address); |
441 | return; | 475 | return; |
442 | 476 | ||
443 | /* | 477 | /* |
444 | * We ran out of memory, or some other thing happened to us that made | 478 | * We ran out of memory, or some other thing happened to us that made |
445 | * us unable to handle the page fault gracefully. | 479 | * us unable to handle the page fault gracefully. |
446 | */ | 480 | */ |
447 | out_of_memory: | 481 | out_of_memory: |
448 | insn = get_fault_insn(regs, insn); | 482 | insn = get_fault_insn(regs, insn); |
449 | up_read(&mm->mmap_sem); | 483 | up_read(&mm->mmap_sem); |
450 | printk("VM: killing process %s\n", current->comm); | 484 | printk("VM: killing process %s\n", current->comm); |
451 | if (!(regs->tstate & TSTATE_PRIV)) | 485 | if (!(regs->tstate & TSTATE_PRIV)) |
452 | do_exit(SIGKILL); | 486 | do_exit(SIGKILL); |
453 | goto handle_kernel_fault; | 487 | goto handle_kernel_fault; |
454 | 488 | ||
455 | intr_or_no_mm: | 489 | intr_or_no_mm: |
456 | insn = get_fault_insn(regs, 0); | 490 | insn = get_fault_insn(regs, 0); |
457 | goto handle_kernel_fault; | 491 | goto handle_kernel_fault; |
458 | 492 | ||
459 | do_sigbus: | 493 | do_sigbus: |
460 | insn = get_fault_insn(regs, insn); | 494 | insn = get_fault_insn(regs, insn); |
461 | up_read(&mm->mmap_sem); | 495 | up_read(&mm->mmap_sem); |
462 | 496 | ||
463 | /* | 497 | /* |
464 | * Send a sigbus, regardless of whether we were in kernel | 498 | * Send a sigbus, regardless of whether we were in kernel |
465 | * or user mode. | 499 | * or user mode. |
466 | */ | 500 | */ |
467 | do_fault_siginfo(BUS_ADRERR, SIGBUS, regs, insn, fault_code); | 501 | do_fault_siginfo(BUS_ADRERR, SIGBUS, regs, insn, fault_code); |
468 | 502 | ||
469 | /* Kernel mode? Handle exceptions or die */ | 503 | /* Kernel mode? Handle exceptions or die */ |
470 | if (regs->tstate & TSTATE_PRIV) | 504 | if (regs->tstate & TSTATE_PRIV) |
471 | goto handle_kernel_fault; | 505 | goto handle_kernel_fault; |
472 | } | 506 | } |
473 | 507 |
include/asm-sparc64/kdebug.h
1 | #ifndef _SPARC64_KDEBUG_H | 1 | #ifndef _SPARC64_KDEBUG_H |
2 | #define _SPARC64_KDEBUG_H | 2 | #define _SPARC64_KDEBUG_H |
3 | 3 | ||
4 | /* Nearly identical to x86_64/i386 code. */ | 4 | /* Nearly identical to x86_64/i386 code. */ |
5 | 5 | ||
6 | #include <linux/notifier.h> | 6 | #include <linux/notifier.h> |
7 | 7 | ||
8 | struct pt_regs; | 8 | struct pt_regs; |
9 | 9 | ||
10 | struct die_args { | 10 | struct die_args { |
11 | struct pt_regs *regs; | 11 | struct pt_regs *regs; |
12 | const char *str; | 12 | const char *str; |
13 | long err; | 13 | long err; |
14 | int trapnr; | 14 | int trapnr; |
15 | int signr; | 15 | int signr; |
16 | }; | 16 | }; |
17 | 17 | ||
18 | extern int register_die_notifier(struct notifier_block *); | 18 | extern int register_die_notifier(struct notifier_block *); |
19 | extern int unregister_die_notifier(struct notifier_block *); | 19 | extern int unregister_die_notifier(struct notifier_block *); |
20 | extern int register_page_fault_notifier(struct notifier_block *); | ||
21 | extern int unregister_page_fault_notifier(struct notifier_block *); | ||
20 | extern struct atomic_notifier_head sparc64die_chain; | 22 | extern struct atomic_notifier_head sparc64die_chain; |
21 | 23 | ||
22 | extern void bad_trap(struct pt_regs *, long); | 24 | extern void bad_trap(struct pt_regs *, long); |
23 | 25 | ||
24 | /* Grossly misnamed. */ | 26 | /* Grossly misnamed. */ |
25 | enum die_val { | 27 | enum die_val { |
26 | DIE_OOPS = 1, | 28 | DIE_OOPS = 1, |
27 | DIE_DEBUG, /* ta 0x70 */ | 29 | DIE_DEBUG, /* ta 0x70 */ |
28 | DIE_DEBUG_2, /* ta 0x71 */ | 30 | DIE_DEBUG_2, /* ta 0x71 */ |
29 | DIE_DIE, | 31 | DIE_DIE, |
30 | DIE_TRAP, | 32 | DIE_TRAP, |
31 | DIE_TRAP_TL1, | 33 | DIE_TRAP_TL1, |
32 | DIE_GPF, | 34 | DIE_GPF, |
33 | DIE_CALL, | 35 | DIE_CALL, |
34 | DIE_PAGE_FAULT, | 36 | DIE_PAGE_FAULT, |
35 | }; | 37 | }; |
36 | 38 | ||
37 | static inline int notify_die(enum die_val val,char *str, struct pt_regs *regs, | 39 | static inline int notify_die(enum die_val val,char *str, struct pt_regs *regs, |
38 | long err, int trap, int sig) | 40 | long err, int trap, int sig) |
39 | { | 41 | { |
40 | struct die_args args = { .regs = regs, | 42 | struct die_args args = { .regs = regs, |
41 | .str = str, | 43 | .str = str, |
42 | .err = err, | 44 | .err = err, |
43 | .trapnr = trap, | 45 | .trapnr = trap, |
44 | .signr = sig }; | 46 | .signr = sig }; |
45 | 47 | ||
46 | return atomic_notifier_call_chain(&sparc64die_chain, val, &args); | 48 | return atomic_notifier_call_chain(&sparc64die_chain, val, &args); |
47 | } | 49 | } |
48 | 50 | ||
49 | #endif | 51 | #endif |
50 | 52 |