diff options
Diffstat (limited to 'arch/blackfin/kernel/traps.c')
-rw-r--r-- | arch/blackfin/kernel/traps.c | 83 |
1 files changed, 71 insertions, 12 deletions
diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c index 6b7325d634af..ba70c4bc2699 100644 --- a/arch/blackfin/kernel/traps.c +++ b/arch/blackfin/kernel/traps.c | |||
@@ -119,6 +119,15 @@ static void decode_address(char *buf, unsigned long address) | |||
119 | return; | 119 | return; |
120 | } | 120 | } |
121 | 121 | ||
122 | /* | ||
123 | * Don't walk any of the vmas if we are oopsing, it has been known | ||
124 | * to cause problems - corrupt vmas (kernel crashes) cause double faults | ||
125 | */ | ||
126 | if (oops_in_progress) { | ||
127 | strcat(buf, "/* kernel dynamic memory (maybe user-space) */"); | ||
128 | return; | ||
129 | } | ||
130 | |||
122 | /* looks like we're off in user-land, so let's walk all the | 131 | /* looks like we're off in user-land, so let's walk all the |
123 | * mappings of all our processes and see if we can't be a whee | 132 | * mappings of all our processes and see if we can't be a whee |
124 | * bit more specific | 133 | * bit more specific |
@@ -129,6 +138,12 @@ static void decode_address(char *buf, unsigned long address) | |||
129 | if (!mm) | 138 | if (!mm) |
130 | continue; | 139 | continue; |
131 | 140 | ||
141 | if (!down_read_trylock(&mm->mmap_sem)) { | ||
142 | if (!in_atomic) | ||
143 | mmput(mm); | ||
144 | continue; | ||
145 | } | ||
146 | |||
132 | for (n = rb_first(&mm->mm_rb); n; n = rb_next(n)) { | 147 | for (n = rb_first(&mm->mm_rb); n; n = rb_next(n)) { |
133 | struct vm_area_struct *vma; | 148 | struct vm_area_struct *vma; |
134 | 149 | ||
@@ -168,6 +183,7 @@ static void decode_address(char *buf, unsigned long address) | |||
168 | sprintf(buf, "[ %s vma:0x%lx-0x%lx]", | 183 | sprintf(buf, "[ %s vma:0x%lx-0x%lx]", |
169 | name, vma->vm_start, vma->vm_end); | 184 | name, vma->vm_start, vma->vm_end); |
170 | 185 | ||
186 | up_read(&mm->mmap_sem); | ||
171 | if (!in_atomic) | 187 | if (!in_atomic) |
172 | mmput(mm); | 188 | mmput(mm); |
173 | 189 | ||
@@ -177,11 +193,16 @@ static void decode_address(char *buf, unsigned long address) | |||
177 | goto done; | 193 | goto done; |
178 | } | 194 | } |
179 | } | 195 | } |
196 | |||
197 | up_read(&mm->mmap_sem); | ||
180 | if (!in_atomic) | 198 | if (!in_atomic) |
181 | mmput(mm); | 199 | mmput(mm); |
182 | } | 200 | } |
183 | 201 | ||
184 | /* we were unable to find this address anywhere */ | 202 | /* |
203 | * we were unable to find this address anywhere, | ||
204 | * or some MMs were skipped because they were in use. | ||
205 | */ | ||
185 | sprintf(buf, "/* kernel dynamic memory */"); | 206 | sprintf(buf, "/* kernel dynamic memory */"); |
186 | 207 | ||
187 | done: | 208 | done: |
@@ -239,9 +260,7 @@ asmlinkage notrace void trap_c(struct pt_regs *fp) | |||
239 | #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON | 260 | #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON |
240 | int j; | 261 | int j; |
241 | #endif | 262 | #endif |
242 | #ifdef CONFIG_DEBUG_HUNT_FOR_ZERO | ||
243 | unsigned int cpu = raw_smp_processor_id(); | 263 | unsigned int cpu = raw_smp_processor_id(); |
244 | #endif | ||
245 | const char *strerror = NULL; | 264 | const char *strerror = NULL; |
246 | int sig = 0; | 265 | int sig = 0; |
247 | siginfo_t info; | 266 | siginfo_t info; |
@@ -515,6 +534,36 @@ asmlinkage notrace void trap_c(struct pt_regs *fp) | |||
515 | break; | 534 | break; |
516 | /* External Memory Addressing Error */ | 535 | /* External Memory Addressing Error */ |
517 | case (SEQSTAT_HWERRCAUSE_EXTERN_ADDR): | 536 | case (SEQSTAT_HWERRCAUSE_EXTERN_ADDR): |
537 | if (ANOMALY_05000310) { | ||
538 | static unsigned long anomaly_rets; | ||
539 | |||
540 | if ((fp->pc >= (L1_CODE_START + L1_CODE_LENGTH - 512)) && | ||
541 | (fp->pc < (L1_CODE_START + L1_CODE_LENGTH))) { | ||
542 | /* | ||
543 | * A false hardware error will happen while fetching at | ||
544 | * the L1 instruction SRAM boundary. Ignore it. | ||
545 | */ | ||
546 | anomaly_rets = fp->rets; | ||
547 | goto traps_done; | ||
548 | } else if (fp->rets == anomaly_rets) { | ||
549 | /* | ||
550 | * While boundary code returns to a function, at the ret | ||
551 | * point, a new false hardware error might occur too based | ||
552 | * on tests. Ignore it too. | ||
553 | */ | ||
554 | goto traps_done; | ||
555 | } else if ((fp->rets >= (L1_CODE_START + L1_CODE_LENGTH - 512)) && | ||
556 | (fp->rets < (L1_CODE_START + L1_CODE_LENGTH))) { | ||
557 | /* | ||
558 | * If boundary code calls a function, at the entry point, | ||
559 | * a new false hardware error maybe happen based on tests. | ||
560 | * Ignore it too. | ||
561 | */ | ||
562 | goto traps_done; | ||
563 | } else | ||
564 | anomaly_rets = 0; | ||
565 | } | ||
566 | |||
518 | info.si_code = BUS_ADRERR; | 567 | info.si_code = BUS_ADRERR; |
519 | sig = SIGBUS; | 568 | sig = SIGBUS; |
520 | strerror = KERN_NOTICE HWC_x3(KERN_NOTICE); | 569 | strerror = KERN_NOTICE HWC_x3(KERN_NOTICE); |
@@ -600,7 +649,17 @@ asmlinkage notrace void trap_c(struct pt_regs *fp) | |||
600 | { | 649 | { |
601 | info.si_signo = sig; | 650 | info.si_signo = sig; |
602 | info.si_errno = 0; | 651 | info.si_errno = 0; |
603 | info.si_addr = (void __user *)fp->pc; | 652 | switch (trapnr) { |
653 | case VEC_CPLB_VL: | ||
654 | case VEC_MISALI_D: | ||
655 | case VEC_CPLB_M: | ||
656 | case VEC_CPLB_MHIT: | ||
657 | info.si_addr = (void __user *)cpu_pda[cpu].dcplb_fault_addr; | ||
658 | break; | ||
659 | default: | ||
660 | info.si_addr = (void __user *)fp->pc; | ||
661 | break; | ||
662 | } | ||
604 | force_sig_info(sig, &info, current); | 663 | force_sig_info(sig, &info, current); |
605 | } | 664 | } |
606 | 665 | ||
@@ -619,7 +678,7 @@ asmlinkage notrace void trap_c(struct pt_regs *fp) | |||
619 | 678 | ||
620 | /* | 679 | /* |
621 | * Similar to get_user, do some address checking, then dereference | 680 | * Similar to get_user, do some address checking, then dereference |
622 | * Return true on sucess, false on bad address | 681 | * Return true on success, false on bad address |
623 | */ | 682 | */ |
624 | static bool get_instruction(unsigned short *val, unsigned short *address) | 683 | static bool get_instruction(unsigned short *val, unsigned short *address) |
625 | { | 684 | { |
@@ -673,7 +732,7 @@ static void decode_instruction(unsigned short *address) | |||
673 | verbose_printk("RTE"); | 732 | verbose_printk("RTE"); |
674 | else if (opcode == 0x0025) | 733 | else if (opcode == 0x0025) |
675 | verbose_printk("EMUEXCPT"); | 734 | verbose_printk("EMUEXCPT"); |
676 | else if (opcode == 0x0040 && opcode <= 0x0047) | 735 | else if (opcode >= 0x0040 && opcode <= 0x0047) |
677 | verbose_printk("STI R%i", opcode & 7); | 736 | verbose_printk("STI R%i", opcode & 7); |
678 | else if (opcode >= 0x0050 && opcode <= 0x0057) | 737 | else if (opcode >= 0x0050 && opcode <= 0x0057) |
679 | verbose_printk("JUMP (P%i)", opcode & 7); | 738 | verbose_printk("JUMP (P%i)", opcode & 7); |
@@ -976,12 +1035,12 @@ void dump_bfin_process(struct pt_regs *fp) | |||
976 | !((unsigned long)current & 0x3) && current->pid) { | 1035 | !((unsigned long)current & 0x3) && current->pid) { |
977 | verbose_printk(KERN_NOTICE "CURRENT PROCESS:\n"); | 1036 | verbose_printk(KERN_NOTICE "CURRENT PROCESS:\n"); |
978 | if (current->comm >= (char *)FIXED_CODE_START) | 1037 | if (current->comm >= (char *)FIXED_CODE_START) |
979 | verbose_printk(KERN_NOTICE "COMM=%s PID=%d\n", | 1038 | verbose_printk(KERN_NOTICE "COMM=%s PID=%d", |
980 | current->comm, current->pid); | 1039 | current->comm, current->pid); |
981 | else | 1040 | else |
982 | verbose_printk(KERN_NOTICE "COMM= invalid\n"); | 1041 | verbose_printk(KERN_NOTICE "COMM= invalid"); |
983 | 1042 | ||
984 | printk(KERN_NOTICE "CPU = %d\n", current_thread_info()->cpu); | 1043 | printk(KERN_CONT " CPU=%d\n", current_thread_info()->cpu); |
985 | if (!((unsigned long)current->mm & 0x3) && (unsigned long)current->mm >= FIXED_CODE_START) | 1044 | if (!((unsigned long)current->mm & 0x3) && (unsigned long)current->mm >= FIXED_CODE_START) |
986 | verbose_printk(KERN_NOTICE | 1045 | verbose_printk(KERN_NOTICE |
987 | "TEXT = 0x%p-0x%p DATA = 0x%p-0x%p\n" | 1046 | "TEXT = 0x%p-0x%p DATA = 0x%p-0x%p\n" |
@@ -1057,7 +1116,7 @@ void dump_bfin_mem(struct pt_regs *fp) | |||
1057 | /* And the last RETI points to the current userspace context */ | 1116 | /* And the last RETI points to the current userspace context */ |
1058 | if ((fp + 1)->pc >= current->mm->start_code && | 1117 | if ((fp + 1)->pc >= current->mm->start_code && |
1059 | (fp + 1)->pc <= current->mm->end_code) { | 1118 | (fp + 1)->pc <= current->mm->end_code) { |
1060 | verbose_printk(KERN_NOTICE "It might be better to look around here : \n"); | 1119 | verbose_printk(KERN_NOTICE "It might be better to look around here :\n"); |
1061 | verbose_printk(KERN_NOTICE "-------------------------------------------\n"); | 1120 | verbose_printk(KERN_NOTICE "-------------------------------------------\n"); |
1062 | show_regs(fp + 1); | 1121 | show_regs(fp + 1); |
1063 | verbose_printk(KERN_NOTICE "-------------------------------------------\n"); | 1122 | verbose_printk(KERN_NOTICE "-------------------------------------------\n"); |
@@ -1140,7 +1199,7 @@ void show_regs(struct pt_regs *fp) | |||
1140 | if (fp->ipend & ~0x3F) { | 1199 | if (fp->ipend & ~0x3F) { |
1141 | for (i = 0; i < (NR_IRQS - 1); i++) { | 1200 | for (i = 0; i < (NR_IRQS - 1); i++) { |
1142 | if (!in_atomic) | 1201 | if (!in_atomic) |
1143 | spin_lock_irqsave(&irq_desc[i].lock, flags); | 1202 | raw_spin_lock_irqsave(&irq_desc[i].lock, flags); |
1144 | 1203 | ||
1145 | action = irq_desc[i].action; | 1204 | action = irq_desc[i].action; |
1146 | if (!action) | 1205 | if (!action) |
@@ -1155,7 +1214,7 @@ void show_regs(struct pt_regs *fp) | |||
1155 | verbose_printk("\n"); | 1214 | verbose_printk("\n"); |
1156 | unlock: | 1215 | unlock: |
1157 | if (!in_atomic) | 1216 | if (!in_atomic) |
1158 | spin_unlock_irqrestore(&irq_desc[i].lock, flags); | 1217 | raw_spin_unlock_irqrestore(&irq_desc[i].lock, flags); |
1159 | } | 1218 | } |
1160 | } | 1219 | } |
1161 | 1220 | ||