aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc/mm/fault_32.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc/mm/fault_32.c')
-rw-r--r--arch/sparc/mm/fault_32.c207
1 files changed, 45 insertions, 162 deletions
diff --git a/arch/sparc/mm/fault_32.c b/arch/sparc/mm/fault_32.c
index df3155a17991..f46cf6be3370 100644
--- a/arch/sparc/mm/fault_32.c
+++ b/arch/sparc/mm/fault_32.c
@@ -24,29 +24,19 @@
24 24
25#include <asm/page.h> 25#include <asm/page.h>
26#include <asm/pgtable.h> 26#include <asm/pgtable.h>
27#include <asm/memreg.h>
28#include <asm/openprom.h> 27#include <asm/openprom.h>
29#include <asm/oplib.h> 28#include <asm/oplib.h>
30#include <asm/smp.h> 29#include <asm/smp.h>
31#include <asm/traps.h> 30#include <asm/traps.h>
32#include <asm/uaccess.h> 31#include <asm/uaccess.h>
33 32
34extern int prom_node_root;
35
36int show_unhandled_signals = 1; 33int show_unhandled_signals = 1;
37 34
38/* At boot time we determine these two values necessary for setting 35/* At boot time we determine these two values necessary for setting
39 * up the segment maps and page table entries (pte's). 36 * up the segment maps and page table entries (pte's).
40 */ 37 */
41 38
42int num_segmaps, num_contexts; 39int num_contexts;
43int invalid_segment;
44
45/* various Virtual Address Cache parameters we find at boot time... */
46
47int vac_size, vac_linesize, vac_do_hw_vac_flushes;
48int vac_entries_per_context, vac_entries_per_segment;
49int vac_entries_per_page;
50 40
51/* Return how much physical memory we have. */ 41/* Return how much physical memory we have. */
52unsigned long probe_memory(void) 42unsigned long probe_memory(void)
@@ -60,55 +50,36 @@ unsigned long probe_memory(void)
60 return total; 50 return total;
61} 51}
62 52
63extern void sun4c_complete_all_stores(void);
64
65/* Whee, a level 15 NMI interrupt memory error. Let's have fun... */
66asmlinkage void sparc_lvl15_nmi(struct pt_regs *regs, unsigned long serr,
67 unsigned long svaddr, unsigned long aerr,
68 unsigned long avaddr)
69{
70 sun4c_complete_all_stores();
71 printk("FAULT: NMI received\n");
72 printk("SREGS: Synchronous Error %08lx\n", serr);
73 printk(" Synchronous Vaddr %08lx\n", svaddr);
74 printk(" Asynchronous Error %08lx\n", aerr);
75 printk(" Asynchronous Vaddr %08lx\n", avaddr);
76 if (sun4c_memerr_reg)
77 printk(" Memory Parity Error %08lx\n", *sun4c_memerr_reg);
78 printk("REGISTER DUMP:\n");
79 show_regs(regs);
80 prom_halt();
81}
82
83static void unhandled_fault(unsigned long, struct task_struct *, 53static void unhandled_fault(unsigned long, struct task_struct *,
84 struct pt_regs *) __attribute__ ((noreturn)); 54 struct pt_regs *) __attribute__ ((noreturn));
85 55
86static void unhandled_fault(unsigned long address, struct task_struct *tsk, 56static void __noreturn unhandled_fault(unsigned long address,
87 struct pt_regs *regs) 57 struct task_struct *tsk,
58 struct pt_regs *regs)
88{ 59{
89 if((unsigned long) address < PAGE_SIZE) { 60 if ((unsigned long) address < PAGE_SIZE) {
90 printk(KERN_ALERT 61 printk(KERN_ALERT
91 "Unable to handle kernel NULL pointer dereference\n"); 62 "Unable to handle kernel NULL pointer dereference\n");
92 } else { 63 } else {
93 printk(KERN_ALERT "Unable to handle kernel paging request " 64 printk(KERN_ALERT "Unable to handle kernel paging request at virtual address %08lx\n",
94 "at virtual address %08lx\n", address); 65 address);
95 } 66 }
96 printk(KERN_ALERT "tsk->{mm,active_mm}->context = %08lx\n", 67 printk(KERN_ALERT "tsk->{mm,active_mm}->context = %08lx\n",
97 (tsk->mm ? tsk->mm->context : tsk->active_mm->context)); 68 (tsk->mm ? tsk->mm->context : tsk->active_mm->context));
98 printk(KERN_ALERT "tsk->{mm,active_mm}->pgd = %08lx\n", 69 printk(KERN_ALERT "tsk->{mm,active_mm}->pgd = %08lx\n",
99 (tsk->mm ? (unsigned long) tsk->mm->pgd : 70 (tsk->mm ? (unsigned long) tsk->mm->pgd :
100 (unsigned long) tsk->active_mm->pgd)); 71 (unsigned long) tsk->active_mm->pgd));
101 die_if_kernel("Oops", regs); 72 die_if_kernel("Oops", regs);
102} 73}
103 74
104asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc, 75asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc,
105 unsigned long address) 76 unsigned long address)
106{ 77{
107 struct pt_regs regs; 78 struct pt_regs regs;
108 unsigned long g2; 79 unsigned long g2;
109 unsigned int insn; 80 unsigned int insn;
110 int i; 81 int i;
111 82
112 i = search_extables_range(ret_pc, &g2); 83 i = search_extables_range(ret_pc, &g2);
113 switch (i) { 84 switch (i) {
114 case 3: 85 case 3:
@@ -128,14 +99,14 @@ asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc,
128 /* for _from_ macros */ 99 /* for _from_ macros */
129 insn = *((unsigned int *) pc); 100 insn = *((unsigned int *) pc);
130 if (!((insn >> 21) & 1) || ((insn>>19)&0x3f) == 15) 101 if (!((insn >> 21) & 1) || ((insn>>19)&0x3f) == 15)
131 return 2; 102 return 2;
132 break; 103 break;
133 104
134 default: 105 default:
135 break; 106 break;
136 } 107 }
137 108
138 memset(&regs, 0, sizeof (regs)); 109 memset(&regs, 0, sizeof(regs));
139 regs.pc = pc; 110 regs.pc = pc;
140 regs.npc = pc + 4; 111 regs.npc = pc + 4;
141 __asm__ __volatile__( 112 __asm__ __volatile__(
@@ -198,11 +169,10 @@ static unsigned long compute_si_addr(struct pt_regs *regs, int text_fault)
198 if (text_fault) 169 if (text_fault)
199 return regs->pc; 170 return regs->pc;
200 171
201 if (regs->psr & PSR_PS) { 172 if (regs->psr & PSR_PS)
202 insn = *(unsigned int *) regs->pc; 173 insn = *(unsigned int *) regs->pc;
203 } else { 174 else
204 __get_user(insn, (unsigned int *) regs->pc); 175 __get_user(insn, (unsigned int *) regs->pc);
205 }
206 176
207 return safe_compute_effective_address(regs, insn); 177 return safe_compute_effective_address(regs, insn);
208} 178}
@@ -228,7 +198,7 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
228 unsigned int flags = (FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE | 198 unsigned int flags = (FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
229 (write ? FAULT_FLAG_WRITE : 0)); 199 (write ? FAULT_FLAG_WRITE : 0));
230 200
231 if(text_fault) 201 if (text_fault)
232 address = regs->pc; 202 address = regs->pc;
233 203
234 /* 204 /*
@@ -241,36 +211,32 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
241 * nothing more. 211 * nothing more.
242 */ 212 */
243 code = SEGV_MAPERR; 213 code = SEGV_MAPERR;
244 if (!ARCH_SUN4C && address >= TASK_SIZE) 214 if (address >= TASK_SIZE)
245 goto vmalloc_fault; 215 goto vmalloc_fault;
246 216
247 /* 217 /*
248 * If we're in an interrupt or have no user 218 * If we're in an interrupt or have no user
249 * context, we must not take the fault.. 219 * context, we must not take the fault..
250 */ 220 */
251 if (in_atomic() || !mm) 221 if (in_atomic() || !mm)
252 goto no_context; 222 goto no_context;
253 223
254 perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address); 224 perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
255 225
256retry: 226retry:
257 down_read(&mm->mmap_sem); 227 down_read(&mm->mmap_sem);
258 228
259 /* 229 if (!from_user && address >= PAGE_OFFSET)
260 * The kernel referencing a bad kernel pointer can lock up
261 * a sun4c machine completely, so we must attempt recovery.
262 */
263 if(!from_user && address >= PAGE_OFFSET)
264 goto bad_area; 230 goto bad_area;
265 231
266 vma = find_vma(mm, address); 232 vma = find_vma(mm, address);
267 if(!vma) 233 if (!vma)
268 goto bad_area; 234 goto bad_area;
269 if(vma->vm_start <= address) 235 if (vma->vm_start <= address)
270 goto good_area; 236 goto good_area;
271 if(!(vma->vm_flags & VM_GROWSDOWN)) 237 if (!(vma->vm_flags & VM_GROWSDOWN))
272 goto bad_area; 238 goto bad_area;
273 if(expand_stack(vma, address)) 239 if (expand_stack(vma, address))
274 goto bad_area; 240 goto bad_area;
275 /* 241 /*
276 * Ok, we have a good vm_area for this memory access, so 242 * Ok, we have a good vm_area for this memory access, so
@@ -278,12 +244,12 @@ retry:
278 */ 244 */
279good_area: 245good_area:
280 code = SEGV_ACCERR; 246 code = SEGV_ACCERR;
281 if(write) { 247 if (write) {
282 if(!(vma->vm_flags & VM_WRITE)) 248 if (!(vma->vm_flags & VM_WRITE))
283 goto bad_area; 249 goto bad_area;
284 } else { 250 } else {
285 /* Allow reads even for write-only mappings */ 251 /* Allow reads even for write-only mappings */
286 if(!(vma->vm_flags & (VM_READ | VM_EXEC))) 252 if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
287 goto bad_area; 253 goto bad_area;
288 } 254 }
289 255
@@ -349,14 +315,16 @@ no_context:
349 g2 = regs->u_regs[UREG_G2]; 315 g2 = regs->u_regs[UREG_G2];
350 if (!from_user) { 316 if (!from_user) {
351 fixup = search_extables_range(regs->pc, &g2); 317 fixup = search_extables_range(regs->pc, &g2);
352 if (fixup > 10) { /* Values below are reserved for other things */ 318 /* Values below 10 are reserved for other things */
319 if (fixup > 10) {
353 extern const unsigned __memset_start[]; 320 extern const unsigned __memset_start[];
354 extern const unsigned __memset_end[]; 321 extern const unsigned __memset_end[];
355 extern const unsigned __csum_partial_copy_start[]; 322 extern const unsigned __csum_partial_copy_start[];
356 extern const unsigned __csum_partial_copy_end[]; 323 extern const unsigned __csum_partial_copy_end[];
357 324
358#ifdef DEBUG_EXCEPTIONS 325#ifdef DEBUG_EXCEPTIONS
359 printk("Exception: PC<%08lx> faddr<%08lx>\n", regs->pc, address); 326 printk("Exception: PC<%08lx> faddr<%08lx>\n",
327 regs->pc, address);
360 printk("EX_TABLE: insn<%08lx> fixup<%08x> g2<%08lx>\n", 328 printk("EX_TABLE: insn<%08lx> fixup<%08x> g2<%08lx>\n",
361 regs->pc, fixup, g2); 329 regs->pc, fixup, g2);
362#endif 330#endif
@@ -364,7 +332,7 @@ no_context:
364 regs->pc < (unsigned long)__memset_end) || 332 regs->pc < (unsigned long)__memset_end) ||
365 (regs->pc >= (unsigned long)__csum_partial_copy_start && 333 (regs->pc >= (unsigned long)__csum_partial_copy_start &&
366 regs->pc < (unsigned long)__csum_partial_copy_end)) { 334 regs->pc < (unsigned long)__csum_partial_copy_end)) {
367 regs->u_regs[UREG_I4] = address; 335 regs->u_regs[UREG_I4] = address;
368 regs->u_regs[UREG_I5] = regs->pc; 336 regs->u_regs[UREG_I5] = regs->pc;
369 } 337 }
370 regs->u_regs[UREG_G2] = g2; 338 regs->u_regs[UREG_G2] = g2;
@@ -373,8 +341,8 @@ no_context:
373 return; 341 return;
374 } 342 }
375 } 343 }
376 344
377 unhandled_fault (address, tsk, regs); 345 unhandled_fault(address, tsk, regs);
378 do_exit(SIGKILL); 346 do_exit(SIGKILL);
379 347
380/* 348/*
@@ -420,97 +388,12 @@ vmalloc_fault:
420 388
421 if (pmd_present(*pmd) || !pmd_present(*pmd_k)) 389 if (pmd_present(*pmd) || !pmd_present(*pmd_k))
422 goto bad_area_nosemaphore; 390 goto bad_area_nosemaphore;
391
423 *pmd = *pmd_k; 392 *pmd = *pmd_k;
424 return; 393 return;
425 } 394 }
426} 395}
427 396
428asmlinkage void do_sun4c_fault(struct pt_regs *regs, int text_fault, int write,
429 unsigned long address)
430{
431 extern void sun4c_update_mmu_cache(struct vm_area_struct *,
432 unsigned long,pte_t *);
433 extern pte_t *sun4c_pte_offset_kernel(pmd_t *,unsigned long);
434 struct task_struct *tsk = current;
435 struct mm_struct *mm = tsk->mm;
436 pgd_t *pgdp;
437 pte_t *ptep;
438
439 if (text_fault) {
440 address = regs->pc;
441 } else if (!write &&
442 !(regs->psr & PSR_PS)) {
443 unsigned int insn, __user *ip;
444
445 ip = (unsigned int __user *)regs->pc;
446 if (!get_user(insn, ip)) {
447 if ((insn & 0xc1680000) == 0xc0680000)
448 write = 1;
449 }
450 }
451
452 if (!mm) {
453 /* We are oopsing. */
454 do_sparc_fault(regs, text_fault, write, address);
455 BUG(); /* P3 Oops already, you bitch */
456 }
457
458 pgdp = pgd_offset(mm, address);
459 ptep = sun4c_pte_offset_kernel((pmd_t *) pgdp, address);
460
461 if (pgd_val(*pgdp)) {
462 if (write) {
463 if ((pte_val(*ptep) & (_SUN4C_PAGE_WRITE|_SUN4C_PAGE_PRESENT))
464 == (_SUN4C_PAGE_WRITE|_SUN4C_PAGE_PRESENT)) {
465 unsigned long flags;
466
467 *ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_ACCESSED |
468 _SUN4C_PAGE_MODIFIED |
469 _SUN4C_PAGE_VALID |
470 _SUN4C_PAGE_DIRTY);
471
472 local_irq_save(flags);
473 if (sun4c_get_segmap(address) != invalid_segment) {
474 sun4c_put_pte(address, pte_val(*ptep));
475 local_irq_restore(flags);
476 return;
477 }
478 local_irq_restore(flags);
479 }
480 } else {
481 if ((pte_val(*ptep) & (_SUN4C_PAGE_READ|_SUN4C_PAGE_PRESENT))
482 == (_SUN4C_PAGE_READ|_SUN4C_PAGE_PRESENT)) {
483 unsigned long flags;
484
485 *ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_ACCESSED |
486 _SUN4C_PAGE_VALID);
487
488 local_irq_save(flags);
489 if (sun4c_get_segmap(address) != invalid_segment) {
490 sun4c_put_pte(address, pte_val(*ptep));
491 local_irq_restore(flags);
492 return;
493 }
494 local_irq_restore(flags);
495 }
496 }
497 }
498
499 /* This conditional is 'interesting'. */
500 if (pgd_val(*pgdp) && !(write && !(pte_val(*ptep) & _SUN4C_PAGE_WRITE))
501 && (pte_val(*ptep) & _SUN4C_PAGE_VALID))
502 /* Note: It is safe to not grab the MMAP semaphore here because
503 * we know that update_mmu_cache() will not sleep for
504 * any reason (at least not in the current implementation)
505 * and therefore there is no danger of another thread getting
506 * on the CPU and doing a shrink_mmap() on this vma.
507 */
508 sun4c_update_mmu_cache (find_vma(current->mm, address), address,
509 ptep);
510 else
511 do_sparc_fault(regs, text_fault, write, address);
512}
513
514/* This always deals with user addresses. */ 397/* This always deals with user addresses. */
515static void force_user_fault(unsigned long address, int write) 398static void force_user_fault(unsigned long address, int write)
516{ 399{
@@ -523,21 +406,21 @@ static void force_user_fault(unsigned long address, int write)
523 406
524 down_read(&mm->mmap_sem); 407 down_read(&mm->mmap_sem);
525 vma = find_vma(mm, address); 408 vma = find_vma(mm, address);
526 if(!vma) 409 if (!vma)
527 goto bad_area; 410 goto bad_area;
528 if(vma->vm_start <= address) 411 if (vma->vm_start <= address)
529 goto good_area; 412 goto good_area;
530 if(!(vma->vm_flags & VM_GROWSDOWN)) 413 if (!(vma->vm_flags & VM_GROWSDOWN))
531 goto bad_area; 414 goto bad_area;
532 if(expand_stack(vma, address)) 415 if (expand_stack(vma, address))
533 goto bad_area; 416 goto bad_area;
534good_area: 417good_area:
535 code = SEGV_ACCERR; 418 code = SEGV_ACCERR;
536 if(write) { 419 if (write) {
537 if(!(vma->vm_flags & VM_WRITE)) 420 if (!(vma->vm_flags & VM_WRITE))
538 goto bad_area; 421 goto bad_area;
539 } else { 422 } else {
540 if(!(vma->vm_flags & (VM_READ | VM_EXEC))) 423 if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
541 goto bad_area; 424 goto bad_area;
542 } 425 }
543 switch (handle_mm_fault(mm, vma, address, write ? FAULT_FLAG_WRITE : 0)) { 426 switch (handle_mm_fault(mm, vma, address, write ? FAULT_FLAG_WRITE : 0)) {
@@ -568,7 +451,7 @@ void window_overflow_fault(void)
568 unsigned long sp; 451 unsigned long sp;
569 452
570 sp = current_thread_info()->rwbuf_stkptrs[0]; 453 sp = current_thread_info()->rwbuf_stkptrs[0];
571 if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK)) 454 if (((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
572 force_user_fault(sp + 0x38, 1); 455 force_user_fault(sp + 0x38, 1);
573 force_user_fault(sp, 1); 456 force_user_fault(sp, 1);
574 457
@@ -577,7 +460,7 @@ void window_overflow_fault(void)
577 460
578void window_underflow_fault(unsigned long sp) 461void window_underflow_fault(unsigned long sp)
579{ 462{
580 if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK)) 463 if (((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
581 force_user_fault(sp + 0x38, 0); 464 force_user_fault(sp + 0x38, 0);
582 force_user_fault(sp, 0); 465 force_user_fault(sp, 0);
583 466
@@ -589,7 +472,7 @@ void window_ret_fault(struct pt_regs *regs)
589 unsigned long sp; 472 unsigned long sp;
590 473
591 sp = regs->u_regs[UREG_FP]; 474 sp = regs->u_regs[UREG_FP];
592 if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK)) 475 if (((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
593 force_user_fault(sp + 0x38, 0); 476 force_user_fault(sp + 0x38, 0);
594 force_user_fault(sp, 0); 477 force_user_fault(sp, 0);
595 478