| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * File:         arch/blackfin/kernel/traps.c | 
|  | 3 | * Based on: | 
|  | 4 | * Author:       Hamish Macdonald | 
|  | 5 | * | 
|  | 6 | * Created: | 
|  | 7 | * Description:  uses S/W interrupt 15 for the system calls | 
|  | 8 | * | 
|  | 9 | * Modified: | 
|  | 10 | *               Copyright 2004-2006 Analog Devices Inc. | 
|  | 11 | * | 
|  | 12 | * Bugs:         Enter bugs at http://blackfin.uclinux.org/ | 
|  | 13 | * | 
|  | 14 | * This program is free software; you can redistribute it and/or modify | 
|  | 15 | * it under the terms of the GNU General Public License as published by | 
|  | 16 | * the Free Software Foundation; either version 2 of the License, or | 
|  | 17 | * (at your option) any later version. | 
|  | 18 | * | 
|  | 19 | * This program is distributed in the hope that it will be useful, | 
|  | 20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | 21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | 22 | * GNU General Public License for more details. | 
|  | 23 | * | 
|  | 24 | * You should have received a copy of the GNU General Public License | 
|  | 25 | * along with this program; if not, see the file COPYING, or write | 
|  | 26 | * to the Free Software Foundation, Inc., | 
|  | 27 | * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA | 
|  | 28 | */ | 
|  | 29 |  | 
| Mike Frysinger | 1f83b8f | 2007-07-12 22:58:21 +0800 | [diff] [blame] | 30 | #include <linux/uaccess.h> | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 31 | #include <linux/interrupt.h> | 
|  | 32 | #include <linux/module.h> | 
|  | 33 | #include <linux/kallsyms.h> | 
| Bryan Wu | d31c5ab | 2007-08-10 13:00:42 -0700 | [diff] [blame] | 34 | #include <linux/fs.h> | 
| David Howells | 8feae13 | 2009-01-08 12:04:47 +0000 | [diff] [blame] | 35 | #include <linux/rbtree.h> | 
| Mike Frysinger | 1f83b8f | 2007-07-12 22:58:21 +0800 | [diff] [blame] | 36 | #include <asm/traps.h> | 
|  | 37 | #include <asm/cacheflush.h> | 
| Mike Frysinger | f4585a0 | 2008-10-13 14:45:21 +0800 | [diff] [blame] | 38 | #include <asm/cplb.h> | 
| Mike Frysinger | 1f83b8f | 2007-07-12 22:58:21 +0800 | [diff] [blame] | 39 | #include <asm/blackfin.h> | 
|  | 40 | #include <asm/irq_handler.h> | 
| Robin Getz | d8f66c8 | 2007-12-24 15:27:56 +0800 | [diff] [blame] | 41 | #include <linux/irq.h> | 
| Mike Frysinger | 1f83b8f | 2007-07-12 22:58:21 +0800 | [diff] [blame] | 42 | #include <asm/trace.h> | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 43 | #include <asm/fixed_code.h> | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 44 |  | 
|  | 45 | #ifdef CONFIG_KGDB | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 46 | # include <linux/kgdb.h> | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 47 |  | 
|  | 48 | # define CHK_DEBUGGER_TRAP() \ | 
|  | 49 | do { \ | 
| Sonic Zhang | a5ac012 | 2008-10-13 14:07:19 +0800 | [diff] [blame] | 50 | kgdb_handle_exception(trapnr, sig, info.si_code, fp); \ | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 51 | } while (0) | 
|  | 52 | # define CHK_DEBUGGER_TRAP_MAYBE() \ | 
|  | 53 | do { \ | 
|  | 54 | if (kgdb_connected) \ | 
|  | 55 | CHK_DEBUGGER_TRAP(); \ | 
|  | 56 | } while (0) | 
|  | 57 | #else | 
|  | 58 | # define CHK_DEBUGGER_TRAP() do { } while (0) | 
|  | 59 | # define CHK_DEBUGGER_TRAP_MAYBE() do { } while (0) | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 60 | #endif | 
|  | 61 |  | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 62 |  | 
| Robin Getz | 4ee1c45 | 2008-10-28 11:36:11 +0800 | [diff] [blame] | 63 | #ifdef CONFIG_DEBUG_VERBOSE | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 64 | #define verbose_printk(fmt, arg...) \ | 
|  | 65 | printk(fmt, ##arg) | 
|  | 66 | #else | 
|  | 67 | #define verbose_printk(fmt, arg...) \ | 
|  | 68 | ({ if (0) printk(fmt, ##arg); 0; }) | 
|  | 69 | #endif | 
|  | 70 |  | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 71 | /* Initiate the event table handler */ | 
|  | 72 | void __init trap_init(void) | 
|  | 73 | { | 
|  | 74 | CSYNC(); | 
|  | 75 | bfin_write_EVT3(trap); | 
|  | 76 | CSYNC(); | 
|  | 77 | } | 
|  | 78 |  | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 79 | static void decode_address(char *buf, unsigned long address) | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 80 | { | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 81 | #ifdef CONFIG_DEBUG_VERBOSE | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 82 | struct vm_list_struct *vml; | 
|  | 83 | struct task_struct *p; | 
|  | 84 | struct mm_struct *mm; | 
| Robin Getz | 885be03 | 2007-10-29 17:20:41 +0800 | [diff] [blame] | 85 | unsigned long flags, offset; | 
| Robin Getz | 904656c | 2008-03-26 09:17:43 +0800 | [diff] [blame] | 86 | unsigned char in_atomic = (bfin_read_IPEND() & 0x10) || in_atomic(); | 
| David Howells | 8feae13 | 2009-01-08 12:04:47 +0000 | [diff] [blame] | 87 | struct rb_node *n; | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 88 |  | 
|  | 89 | #ifdef CONFIG_KALLSYMS | 
| Mike Frysinger | 8a0e665 | 2007-05-21 18:09:19 +0800 | [diff] [blame] | 90 | unsigned long symsize; | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 91 | const char *symname; | 
|  | 92 | char *modname; | 
|  | 93 | char *delim = ":"; | 
|  | 94 | char namebuf[128]; | 
|  | 95 |  | 
|  | 96 | /* look up the address and see if we are in kernel space */ | 
|  | 97 | symname = kallsyms_lookup(address, &symsize, &offset, &modname, namebuf); | 
|  | 98 |  | 
|  | 99 | if (symname) { | 
|  | 100 | /* yeah! kernel space! */ | 
|  | 101 | if (!modname) | 
|  | 102 | modname = delim = ""; | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 103 | sprintf(buf, "<0x%p> { %s%s%s%s + 0x%lx }", | 
| Mike Frysinger | 1f83b8f | 2007-07-12 22:58:21 +0800 | [diff] [blame] | 104 | (void *)address, delim, modname, delim, symname, | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 105 | (unsigned long)offset); | 
| Robin Getz | 885be03 | 2007-10-29 17:20:41 +0800 | [diff] [blame] | 106 | return; | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 107 |  | 
|  | 108 | } | 
|  | 109 | #endif | 
|  | 110 |  | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 111 | /* Problem in fixed code section? */ | 
|  | 112 | if (address >= FIXED_CODE_START && address < FIXED_CODE_END) { | 
|  | 113 | sprintf(buf, "<0x%p> /* Maybe fixed code section */", (void *)address); | 
|  | 114 | return; | 
|  | 115 | } | 
|  | 116 |  | 
|  | 117 | /* Problem somewhere before the kernel start address */ | 
|  | 118 | if (address < CONFIG_BOOT_LOAD) { | 
|  | 119 | sprintf(buf, "<0x%p> /* Maybe null pointer? */", (void *)address); | 
|  | 120 | return; | 
|  | 121 | } | 
|  | 122 |  | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 123 | /* looks like we're off in user-land, so let's walk all the | 
|  | 124 | * mappings of all our processes and see if we can't be a whee | 
|  | 125 | * bit more specific | 
|  | 126 | */ | 
| Robin Getz | 885be03 | 2007-10-29 17:20:41 +0800 | [diff] [blame] | 127 | write_lock_irqsave(&tasklist_lock, flags); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 128 | for_each_process(p) { | 
| Robin Getz | 904656c | 2008-03-26 09:17:43 +0800 | [diff] [blame] | 129 | mm = (in_atomic ? p->mm : get_task_mm(p)); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 130 | if (!mm) | 
|  | 131 | continue; | 
|  | 132 |  | 
| David Howells | 8feae13 | 2009-01-08 12:04:47 +0000 | [diff] [blame] | 133 | for (n = rb_first(&mm->mm_rb); n; n = rb_next(n)) { | 
|  | 134 | struct vm_area_struct *vma; | 
|  | 135 |  | 
|  | 136 | vma = rb_entry(n, struct vm_area_struct, vm_rb); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 137 |  | 
|  | 138 | if (address >= vma->vm_start && address < vma->vm_end) { | 
| Jan Blunck | cf28b48 | 2008-02-14 19:38:44 -0800 | [diff] [blame] | 139 | char _tmpbuf[256]; | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 140 | char *name = p->comm; | 
|  | 141 | struct file *file = vma->vm_file; | 
| Jan Blunck | cf28b48 | 2008-02-14 19:38:44 -0800 | [diff] [blame] | 142 |  | 
| Tim Pepper | 6a0bfff | 2008-10-27 12:18:36 +0800 | [diff] [blame] | 143 | if (file) { | 
|  | 144 | char *d_name = d_path(&file->f_path, _tmpbuf, | 
| Jan Blunck | cf28b48 | 2008-02-14 19:38:44 -0800 | [diff] [blame] | 145 | sizeof(_tmpbuf)); | 
| Tim Pepper | 6a0bfff | 2008-10-27 12:18:36 +0800 | [diff] [blame] | 146 | if (!IS_ERR(d_name)) | 
|  | 147 | name = d_name; | 
|  | 148 | } | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 149 |  | 
| Mike Frysinger | 8a0e665 | 2007-05-21 18:09:19 +0800 | [diff] [blame] | 150 | /* FLAT does not have its text aligned to the start of | 
|  | 151 | * the map while FDPIC ELF does ... | 
|  | 152 | */ | 
| Mike Frysinger | 8a0e665 | 2007-05-21 18:09:19 +0800 | [diff] [blame] | 153 |  | 
| Robin Getz | 7f1c906 | 2008-04-25 03:36:31 +0800 | [diff] [blame] | 154 | /* before we can check flat/fdpic, we need to | 
|  | 155 | * make sure current is valid | 
|  | 156 | */ | 
|  | 157 | if ((unsigned long)current >= FIXED_CODE_START && | 
|  | 158 | !((unsigned long)current & 0x3)) { | 
|  | 159 | if (current->mm && | 
|  | 160 | (address > current->mm->start_code) && | 
|  | 161 | (address < current->mm->end_code)) | 
|  | 162 | offset = address - current->mm->start_code; | 
|  | 163 | else | 
|  | 164 | offset = (address - vma->vm_start) + | 
|  | 165 | (vma->vm_pgoff << PAGE_SHIFT); | 
|  | 166 |  | 
|  | 167 | sprintf(buf, "<0x%p> [ %s + 0x%lx ]", | 
|  | 168 | (void *)address, name, offset); | 
|  | 169 | } else | 
|  | 170 | sprintf(buf, "<0x%p> [ %s vma:0x%lx-0x%lx]", | 
|  | 171 | (void *)address, name, | 
|  | 172 | vma->vm_start, vma->vm_end); | 
|  | 173 |  | 
| Robin Getz | 904656c | 2008-03-26 09:17:43 +0800 | [diff] [blame] | 174 | if (!in_atomic) | 
| Robin Getz | 885be03 | 2007-10-29 17:20:41 +0800 | [diff] [blame] | 175 | mmput(mm); | 
| Robin Getz | 7f1c906 | 2008-04-25 03:36:31 +0800 | [diff] [blame] | 176 |  | 
| Robin Getz | f09630b | 2008-07-26 19:45:46 +0800 | [diff] [blame] | 177 | if (!strlen(buf)) | 
|  | 178 | sprintf(buf, "<0x%p> [ %s ] dynamic memory", (void *)address, name); | 
|  | 179 |  | 
| Robin Getz | 885be03 | 2007-10-29 17:20:41 +0800 | [diff] [blame] | 180 | goto done; | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 181 | } | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 182 | } | 
| Robin Getz | 904656c | 2008-03-26 09:17:43 +0800 | [diff] [blame] | 183 | if (!in_atomic) | 
| Robin Getz | 885be03 | 2007-10-29 17:20:41 +0800 | [diff] [blame] | 184 | mmput(mm); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 185 | } | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 186 |  | 
|  | 187 | /* we were unable to find this address anywhere */ | 
| Robin Getz | f09630b | 2008-07-26 19:45:46 +0800 | [diff] [blame] | 188 | sprintf(buf, "<0x%p> /* kernel dynamic memory */", (void *)address); | 
| Robin Getz | 885be03 | 2007-10-29 17:20:41 +0800 | [diff] [blame] | 189 |  | 
|  | 190 | done: | 
|  | 191 | write_unlock_irqrestore(&tasklist_lock, flags); | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 192 | #else | 
|  | 193 | sprintf(buf, " "); | 
|  | 194 | #endif | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 195 | } | 
|  | 196 |  | 
| Robin Getz | 2ebcade | 2007-10-09 17:24:30 +0800 | [diff] [blame] | 197 | asmlinkage void double_fault_c(struct pt_regs *fp) | 
|  | 198 | { | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 199 | console_verbose(); | 
|  | 200 | oops_in_progress = 1; | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 201 | #ifdef CONFIG_DEBUG_VERBOSE | 
| Robin Getz | 2ebcade | 2007-10-09 17:24:30 +0800 | [diff] [blame] | 202 | printk(KERN_EMERG "\n" KERN_EMERG "Double Fault\n"); | 
| Robin Getz | 0c7a6b2 | 2008-10-08 16:27:12 +0800 | [diff] [blame] | 203 | #ifdef CONFIG_DEBUG_DOUBLEFAULT_PRINT | 
|  | 204 | if (((long)fp->seqstat &  SEQSTAT_EXCAUSE) == VEC_UNCOV) { | 
| Graf Yang | 8f65873 | 2008-11-18 17:48:22 +0800 | [diff] [blame] | 205 | unsigned int cpu = smp_processor_id(); | 
| Robin Getz | 0c7a6b2 | 2008-10-08 16:27:12 +0800 | [diff] [blame] | 206 | char buf[150]; | 
| Graf Yang | 8f65873 | 2008-11-18 17:48:22 +0800 | [diff] [blame] | 207 | decode_address(buf, cpu_pda[cpu].retx); | 
| Robin Getz | 0c7a6b2 | 2008-10-08 16:27:12 +0800 | [diff] [blame] | 208 | printk(KERN_EMERG "While handling exception (EXCAUSE = 0x%x) at %s:\n", | 
| Graf Yang | 8f65873 | 2008-11-18 17:48:22 +0800 | [diff] [blame] | 209 | (unsigned int)cpu_pda[cpu].seqstat & SEQSTAT_EXCAUSE, buf); | 
|  | 210 | decode_address(buf, cpu_pda[cpu].dcplb_fault_addr); | 
| Robin Getz | 0c7a6b2 | 2008-10-08 16:27:12 +0800 | [diff] [blame] | 211 | printk(KERN_NOTICE "   DCPLB_FAULT_ADDR: %s\n", buf); | 
| Graf Yang | 8f65873 | 2008-11-18 17:48:22 +0800 | [diff] [blame] | 212 | decode_address(buf, cpu_pda[cpu].icplb_fault_addr); | 
| Robin Getz | 0c7a6b2 | 2008-10-08 16:27:12 +0800 | [diff] [blame] | 213 | printk(KERN_NOTICE "   ICPLB_FAULT_ADDR: %s\n", buf); | 
|  | 214 |  | 
|  | 215 | decode_address(buf, fp->retx); | 
| Graf Yang | 8f65873 | 2008-11-18 17:48:22 +0800 | [diff] [blame] | 216 | printk(KERN_NOTICE "The instruction at %s caused a double exception\n", buf); | 
| Robin Getz | 0c7a6b2 | 2008-10-08 16:27:12 +0800 | [diff] [blame] | 217 | } else | 
|  | 218 | #endif | 
|  | 219 | { | 
|  | 220 | dump_bfin_process(fp); | 
|  | 221 | dump_bfin_mem(fp); | 
|  | 222 | show_regs(fp); | 
|  | 223 | } | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 224 | #endif | 
| Robin Getz | 2ebcade | 2007-10-09 17:24:30 +0800 | [diff] [blame] | 225 | panic("Double Fault - unrecoverable event\n"); | 
|  | 226 |  | 
|  | 227 | } | 
|  | 228 |  | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 229 | asmlinkage void trap_c(struct pt_regs *fp) | 
|  | 230 | { | 
| Robin Getz | 518039b | 2007-07-25 11:03:28 +0800 | [diff] [blame] | 231 | #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON | 
|  | 232 | int j; | 
|  | 233 | #endif | 
| Graf Yang | 8f65873 | 2008-11-18 17:48:22 +0800 | [diff] [blame] | 234 | #ifdef CONFIG_DEBUG_HUNT_FOR_ZERO | 
|  | 235 | unsigned int cpu = smp_processor_id(); | 
|  | 236 | #endif | 
| Robin Getz | 518039b | 2007-07-25 11:03:28 +0800 | [diff] [blame] | 237 | int sig = 0; | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 238 | siginfo_t info; | 
|  | 239 | unsigned long trapnr = fp->seqstat & SEQSTAT_EXCAUSE; | 
|  | 240 |  | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 241 | trace_buffer_save(j); | 
|  | 242 |  | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 243 | /* Important - be very careful dereferncing pointers - will lead to | 
|  | 244 | * double faults if the stack has become corrupt | 
|  | 245 | */ | 
|  | 246 |  | 
|  | 247 | /* If the fault was caused by a kernel thread, or interrupt handler | 
|  | 248 | * we will kernel panic, so the system reboots. | 
|  | 249 | * If KGDB is enabled, don't set this for kernel breakpoints | 
|  | 250 | */ | 
| Robin Getz | b03b08b | 2007-12-23 22:57:01 +0800 | [diff] [blame] | 251 |  | 
|  | 252 | /* TODO: check to see if we are in some sort of deferred HWERR | 
|  | 253 | * that we should be able to recover from, not kernel panic | 
|  | 254 | */ | 
| Robin Getz | 6b5eace | 2008-01-10 17:57:56 +0800 | [diff] [blame] | 255 | if ((bfin_read_IPEND() & 0xFFC0) && (trapnr != VEC_STEP) | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 256 | #ifdef CONFIG_KGDB | 
| Robin Getz | 6b5eace | 2008-01-10 17:57:56 +0800 | [diff] [blame] | 257 | && (trapnr != VEC_EXCPT02) | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 258 | #endif | 
|  | 259 | ){ | 
|  | 260 | console_verbose(); | 
|  | 261 | oops_in_progress = 1; | 
|  | 262 | } else if (current) { | 
|  | 263 | if (current->mm == NULL) { | 
|  | 264 | console_verbose(); | 
|  | 265 | oops_in_progress = 1; | 
|  | 266 | } | 
|  | 267 | } | 
|  | 268 |  | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 269 | /* trap_c() will be called for exceptions. During exceptions | 
|  | 270 | * processing, the pc value should be set with retx value. | 
|  | 271 | * With this change we can cleanup some code in signal.c- TODO | 
|  | 272 | */ | 
|  | 273 | fp->orig_pc = fp->retx; | 
|  | 274 | /* printk("exception: 0x%x, ipend=%x, reti=%x, retx=%x\n", | 
|  | 275 | trapnr, fp->ipend, fp->pc, fp->retx); */ | 
|  | 276 |  | 
|  | 277 | /* send the appropriate signal to the user program */ | 
|  | 278 | switch (trapnr) { | 
|  | 279 |  | 
|  | 280 | /* This table works in conjuction with the one in ./mach-common/entry.S | 
|  | 281 | * Some exceptions are handled there (in assembly, in exception space) | 
|  | 282 | * Some are handled here, (in C, in interrupt space) | 
|  | 283 | * Some, like CPLB, are handled in both, where the normal path is | 
|  | 284 | * handled in assembly/exception space, and the error path is handled | 
|  | 285 | * here | 
|  | 286 | */ | 
|  | 287 |  | 
|  | 288 | /* 0x00 - Linux Syscall, getting here is an error */ | 
|  | 289 | /* 0x01 - userspace gdb breakpoint, handled here */ | 
|  | 290 | case VEC_EXCPT01: | 
|  | 291 | info.si_code = TRAP_ILLTRAP; | 
|  | 292 | sig = SIGTRAP; | 
|  | 293 | CHK_DEBUGGER_TRAP_MAYBE(); | 
|  | 294 | /* Check if this is a breakpoint in kernel space */ | 
|  | 295 | if (fp->ipend & 0xffc0) | 
|  | 296 | return; | 
|  | 297 | else | 
|  | 298 | break; | 
| Mike Frysinger | 9401e61 | 2007-07-12 11:50:43 +0800 | [diff] [blame] | 299 | /* 0x03 - User Defined, userspace stack overflow */ | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 300 | case VEC_EXCPT03: | 
|  | 301 | info.si_code = SEGV_STACKFLOW; | 
|  | 302 | sig = SIGSEGV; | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 303 | verbose_printk(KERN_NOTICE EXC_0x03(KERN_NOTICE)); | 
| Sonic Zhang | a5ac012 | 2008-10-13 14:07:19 +0800 | [diff] [blame] | 304 | CHK_DEBUGGER_TRAP_MAYBE(); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 305 | break; | 
| Sonic Zhang | 27707d3 | 2008-10-09 14:04:41 +0800 | [diff] [blame] | 306 | /* 0x02 - KGDB initial connection and break signal trap */ | 
|  | 307 | case VEC_EXCPT02: | 
|  | 308 | #ifdef CONFIG_KGDB | 
|  | 309 | info.si_code = TRAP_ILLTRAP; | 
|  | 310 | sig = SIGTRAP; | 
|  | 311 | CHK_DEBUGGER_TRAP(); | 
|  | 312 | return; | 
|  | 313 | #endif | 
| Robin Getz | 5c64e0d | 2008-10-08 14:43:47 +0800 | [diff] [blame] | 314 | /* 0x04 - User Defined */ | 
|  | 315 | /* 0x05 - User Defined */ | 
|  | 316 | /* 0x06 - User Defined */ | 
|  | 317 | /* 0x07 - User Defined */ | 
|  | 318 | /* 0x08 - User Defined */ | 
|  | 319 | /* 0x09 - User Defined */ | 
|  | 320 | /* 0x0A - User Defined */ | 
|  | 321 | /* 0x0B - User Defined */ | 
|  | 322 | /* 0x0C - User Defined */ | 
|  | 323 | /* 0x0D - User Defined */ | 
|  | 324 | /* 0x0E - User Defined */ | 
|  | 325 | /* 0x0F - User Defined */ | 
| Sonic Zhang | 27707d3 | 2008-10-09 14:04:41 +0800 | [diff] [blame] | 326 | /* If we got here, it is most likely that someone was trying to use a | 
| Robin Getz | 5c64e0d | 2008-10-08 14:43:47 +0800 | [diff] [blame] | 327 | * custom exception handler, and it is not actually installed properly | 
|  | 328 | */ | 
|  | 329 | case VEC_EXCPT04 ... VEC_EXCPT15: | 
|  | 330 | info.si_code = ILL_ILLPARAOP; | 
|  | 331 | sig = SIGILL; | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 332 | verbose_printk(KERN_NOTICE EXC_0x04(KERN_NOTICE)); | 
| Robin Getz | 5c64e0d | 2008-10-08 14:43:47 +0800 | [diff] [blame] | 333 | CHK_DEBUGGER_TRAP_MAYBE(); | 
|  | 334 | break; | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 335 | /* 0x10 HW Single step, handled here */ | 
|  | 336 | case VEC_STEP: | 
|  | 337 | info.si_code = TRAP_STEP; | 
|  | 338 | sig = SIGTRAP; | 
|  | 339 | CHK_DEBUGGER_TRAP_MAYBE(); | 
|  | 340 | /* Check if this is a single step in kernel space */ | 
|  | 341 | if (fp->ipend & 0xffc0) | 
|  | 342 | return; | 
|  | 343 | else | 
|  | 344 | break; | 
|  | 345 | /* 0x11 - Trace Buffer Full, handled here */ | 
|  | 346 | case VEC_OVFLOW: | 
|  | 347 | info.si_code = TRAP_TRACEFLOW; | 
|  | 348 | sig = SIGTRAP; | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 349 | verbose_printk(KERN_NOTICE EXC_0x11(KERN_NOTICE)); | 
| Sonic Zhang | a5ac012 | 2008-10-13 14:07:19 +0800 | [diff] [blame] | 350 | CHK_DEBUGGER_TRAP_MAYBE(); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 351 | break; | 
|  | 352 | /* 0x12 - Reserved, Caught by default */ | 
|  | 353 | /* 0x13 - Reserved, Caught by default */ | 
|  | 354 | /* 0x14 - Reserved, Caught by default */ | 
|  | 355 | /* 0x15 - Reserved, Caught by default */ | 
|  | 356 | /* 0x16 - Reserved, Caught by default */ | 
|  | 357 | /* 0x17 - Reserved, Caught by default */ | 
|  | 358 | /* 0x18 - Reserved, Caught by default */ | 
|  | 359 | /* 0x19 - Reserved, Caught by default */ | 
|  | 360 | /* 0x1A - Reserved, Caught by default */ | 
|  | 361 | /* 0x1B - Reserved, Caught by default */ | 
|  | 362 | /* 0x1C - Reserved, Caught by default */ | 
|  | 363 | /* 0x1D - Reserved, Caught by default */ | 
|  | 364 | /* 0x1E - Reserved, Caught by default */ | 
|  | 365 | /* 0x1F - Reserved, Caught by default */ | 
|  | 366 | /* 0x20 - Reserved, Caught by default */ | 
|  | 367 | /* 0x21 - Undefined Instruction, handled here */ | 
|  | 368 | case VEC_UNDEF_I: | 
|  | 369 | info.si_code = ILL_ILLOPC; | 
|  | 370 | sig = SIGILL; | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 371 | verbose_printk(KERN_NOTICE EXC_0x21(KERN_NOTICE)); | 
| Sonic Zhang | a5ac012 | 2008-10-13 14:07:19 +0800 | [diff] [blame] | 372 | CHK_DEBUGGER_TRAP_MAYBE(); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 373 | break; | 
|  | 374 | /* 0x22 - Illegal Instruction Combination, handled here */ | 
|  | 375 | case VEC_ILGAL_I: | 
|  | 376 | info.si_code = ILL_ILLPARAOP; | 
|  | 377 | sig = SIGILL; | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 378 | verbose_printk(KERN_NOTICE EXC_0x22(KERN_NOTICE)); | 
| Sonic Zhang | a5ac012 | 2008-10-13 14:07:19 +0800 | [diff] [blame] | 379 | CHK_DEBUGGER_TRAP_MAYBE(); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 380 | break; | 
| Robin Getz | f26fbc4 | 2007-11-12 22:21:30 +0800 | [diff] [blame] | 381 | /* 0x23 - Data CPLB protection violation, handled here */ | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 382 | case VEC_CPLB_VL: | 
|  | 383 | info.si_code = ILL_CPLB_VI; | 
| Robin Getz | f26fbc4 | 2007-11-12 22:21:30 +0800 | [diff] [blame] | 384 | sig = SIGBUS; | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 385 | verbose_printk(KERN_NOTICE EXC_0x23(KERN_NOTICE)); | 
| Sonic Zhang | a5ac012 | 2008-10-13 14:07:19 +0800 | [diff] [blame] | 386 | CHK_DEBUGGER_TRAP_MAYBE(); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 387 | break; | 
|  | 388 | /* 0x24 - Data access misaligned, handled here */ | 
|  | 389 | case VEC_MISALI_D: | 
|  | 390 | info.si_code = BUS_ADRALN; | 
|  | 391 | sig = SIGBUS; | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 392 | verbose_printk(KERN_NOTICE EXC_0x24(KERN_NOTICE)); | 
| Sonic Zhang | a5ac012 | 2008-10-13 14:07:19 +0800 | [diff] [blame] | 393 | CHK_DEBUGGER_TRAP_MAYBE(); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 394 | break; | 
|  | 395 | /* 0x25 - Unrecoverable Event, handled here */ | 
|  | 396 | case VEC_UNCOV: | 
|  | 397 | info.si_code = ILL_ILLEXCPT; | 
|  | 398 | sig = SIGILL; | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 399 | verbose_printk(KERN_NOTICE EXC_0x25(KERN_NOTICE)); | 
| Sonic Zhang | a5ac012 | 2008-10-13 14:07:19 +0800 | [diff] [blame] | 400 | CHK_DEBUGGER_TRAP_MAYBE(); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 401 | break; | 
|  | 402 | /* 0x26 - Data CPLB Miss, normal case is handled in _cplb_hdr, | 
|  | 403 | error case is handled here */ | 
|  | 404 | case VEC_CPLB_M: | 
|  | 405 | info.si_code = BUS_ADRALN; | 
|  | 406 | sig = SIGBUS; | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 407 | verbose_printk(KERN_NOTICE EXC_0x26(KERN_NOTICE)); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 408 | break; | 
|  | 409 | /* 0x27 - Data CPLB Multiple Hits - Linux Trap Zero, handled here */ | 
|  | 410 | case VEC_CPLB_MHIT: | 
|  | 411 | info.si_code = ILL_CPLB_MULHIT; | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 412 | sig = SIGSEGV; | 
| Mike Frysinger | c6c6f75 | 2008-05-17 16:18:08 +0800 | [diff] [blame] | 413 | #ifdef CONFIG_DEBUG_HUNT_FOR_ZERO | 
| Graf Yang | 8f65873 | 2008-11-18 17:48:22 +0800 | [diff] [blame] | 414 | if (cpu_pda[cpu].dcplb_fault_addr < FIXED_CODE_START) | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 415 | verbose_printk(KERN_NOTICE "NULL pointer access\n"); | 
| Mike Frysinger | c6c6f75 | 2008-05-17 16:18:08 +0800 | [diff] [blame] | 416 | else | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 417 | #endif | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 418 | verbose_printk(KERN_NOTICE EXC_0x27(KERN_NOTICE)); | 
| Sonic Zhang | a5ac012 | 2008-10-13 14:07:19 +0800 | [diff] [blame] | 419 | CHK_DEBUGGER_TRAP_MAYBE(); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 420 | break; | 
|  | 421 | /* 0x28 - Emulation Watchpoint, handled here */ | 
|  | 422 | case VEC_WATCH: | 
|  | 423 | info.si_code = TRAP_WATCHPT; | 
|  | 424 | sig = SIGTRAP; | 
| Robin Getz | 569a50c | 2007-11-21 16:35:57 +0800 | [diff] [blame] | 425 | pr_debug(EXC_0x28(KERN_DEBUG)); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 426 | CHK_DEBUGGER_TRAP_MAYBE(); | 
|  | 427 | /* Check if this is a watchpoint in kernel space */ | 
|  | 428 | if (fp->ipend & 0xffc0) | 
|  | 429 | return; | 
|  | 430 | else | 
|  | 431 | break; | 
|  | 432 | #ifdef CONFIG_BF535 | 
|  | 433 | /* 0x29 - Instruction fetch access error (535 only) */ | 
|  | 434 | case VEC_ISTRU_VL:      /* ADSP-BF535 only (MH) */ | 
|  | 435 | info.si_code = BUS_OPFETCH; | 
|  | 436 | sig = SIGBUS; | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 437 | verbose_printk(KERN_NOTICE "BF535: VEC_ISTRU_VL\n"); | 
| Sonic Zhang | a5ac012 | 2008-10-13 14:07:19 +0800 | [diff] [blame] | 438 | CHK_DEBUGGER_TRAP_MAYBE(); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 439 | break; | 
|  | 440 | #else | 
|  | 441 | /* 0x29 - Reserved, Caught by default */ | 
|  | 442 | #endif | 
|  | 443 | /* 0x2A - Instruction fetch misaligned, handled here */ | 
|  | 444 | case VEC_MISALI_I: | 
|  | 445 | info.si_code = BUS_ADRALN; | 
|  | 446 | sig = SIGBUS; | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 447 | verbose_printk(KERN_NOTICE EXC_0x2A(KERN_NOTICE)); | 
| Sonic Zhang | a5ac012 | 2008-10-13 14:07:19 +0800 | [diff] [blame] | 448 | CHK_DEBUGGER_TRAP_MAYBE(); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 449 | break; | 
| Robin Getz | f26fbc4 | 2007-11-12 22:21:30 +0800 | [diff] [blame] | 450 | /* 0x2B - Instruction CPLB protection violation, handled here */ | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 451 | case VEC_CPLB_I_VL: | 
|  | 452 | info.si_code = ILL_CPLB_VI; | 
| Robin Getz | f26fbc4 | 2007-11-12 22:21:30 +0800 | [diff] [blame] | 453 | sig = SIGBUS; | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 454 | verbose_printk(KERN_NOTICE EXC_0x2B(KERN_NOTICE)); | 
| Sonic Zhang | a5ac012 | 2008-10-13 14:07:19 +0800 | [diff] [blame] | 455 | CHK_DEBUGGER_TRAP_MAYBE(); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 456 | break; | 
|  | 457 | /* 0x2C - Instruction CPLB miss, handled in _cplb_hdr */ | 
|  | 458 | case VEC_CPLB_I_M: | 
|  | 459 | info.si_code = ILL_CPLB_MISS; | 
|  | 460 | sig = SIGBUS; | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 461 | verbose_printk(KERN_NOTICE EXC_0x2C(KERN_NOTICE)); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 462 | break; | 
|  | 463 | /* 0x2D - Instruction CPLB Multiple Hits, handled here */ | 
|  | 464 | case VEC_CPLB_I_MHIT: | 
|  | 465 | info.si_code = ILL_CPLB_MULHIT; | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 466 | sig = SIGSEGV; | 
| Mike Frysinger | c6c6f75 | 2008-05-17 16:18:08 +0800 | [diff] [blame] | 467 | #ifdef CONFIG_DEBUG_HUNT_FOR_ZERO | 
| Graf Yang | 8f65873 | 2008-11-18 17:48:22 +0800 | [diff] [blame] | 468 | if (cpu_pda[cpu].icplb_fault_addr < FIXED_CODE_START) | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 469 | verbose_printk(KERN_NOTICE "Jump to NULL address\n"); | 
| Mike Frysinger | c6c6f75 | 2008-05-17 16:18:08 +0800 | [diff] [blame] | 470 | else | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 471 | #endif | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 472 | verbose_printk(KERN_NOTICE EXC_0x2D(KERN_NOTICE)); | 
| Sonic Zhang | a5ac012 | 2008-10-13 14:07:19 +0800 | [diff] [blame] | 473 | CHK_DEBUGGER_TRAP_MAYBE(); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 474 | break; | 
|  | 475 | /* 0x2E - Illegal use of Supervisor Resource, handled here */ | 
|  | 476 | case VEC_ILL_RES: | 
|  | 477 | info.si_code = ILL_PRVOPC; | 
|  | 478 | sig = SIGILL; | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 479 | verbose_printk(KERN_NOTICE EXC_0x2E(KERN_NOTICE)); | 
| Sonic Zhang | a5ac012 | 2008-10-13 14:07:19 +0800 | [diff] [blame] | 480 | CHK_DEBUGGER_TRAP_MAYBE(); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 481 | break; | 
|  | 482 | /* 0x2F - Reserved, Caught by default */ | 
|  | 483 | /* 0x30 - Reserved, Caught by default */ | 
|  | 484 | /* 0x31 - Reserved, Caught by default */ | 
|  | 485 | /* 0x32 - Reserved, Caught by default */ | 
|  | 486 | /* 0x33 - Reserved, Caught by default */ | 
|  | 487 | /* 0x34 - Reserved, Caught by default */ | 
|  | 488 | /* 0x35 - Reserved, Caught by default */ | 
|  | 489 | /* 0x36 - Reserved, Caught by default */ | 
|  | 490 | /* 0x37 - Reserved, Caught by default */ | 
|  | 491 | /* 0x38 - Reserved, Caught by default */ | 
|  | 492 | /* 0x39 - Reserved, Caught by default */ | 
|  | 493 | /* 0x3A - Reserved, Caught by default */ | 
|  | 494 | /* 0x3B - Reserved, Caught by default */ | 
|  | 495 | /* 0x3C - Reserved, Caught by default */ | 
|  | 496 | /* 0x3D - Reserved, Caught by default */ | 
|  | 497 | /* 0x3E - Reserved, Caught by default */ | 
|  | 498 | /* 0x3F - Reserved, Caught by default */ | 
| Robin Getz | 13fe24f | 2008-01-27 15:38:56 +0800 | [diff] [blame] | 499 | case VEC_HWERR: | 
|  | 500 | info.si_code = BUS_ADRALN; | 
|  | 501 | sig = SIGBUS; | 
|  | 502 | switch (fp->seqstat & SEQSTAT_HWERRCAUSE) { | 
|  | 503 | /* System MMR Error */ | 
|  | 504 | case (SEQSTAT_HWERRCAUSE_SYSTEM_MMR): | 
|  | 505 | info.si_code = BUS_ADRALN; | 
|  | 506 | sig = SIGBUS; | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 507 | verbose_printk(KERN_NOTICE HWC_x2(KERN_NOTICE)); | 
| Robin Getz | 13fe24f | 2008-01-27 15:38:56 +0800 | [diff] [blame] | 508 | break; | 
|  | 509 | /* External Memory Addressing Error */ | 
|  | 510 | case (SEQSTAT_HWERRCAUSE_EXTERN_ADDR): | 
|  | 511 | info.si_code = BUS_ADRERR; | 
|  | 512 | sig = SIGBUS; | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 513 | verbose_printk(KERN_NOTICE HWC_x3(KERN_NOTICE)); | 
| Robin Getz | 13fe24f | 2008-01-27 15:38:56 +0800 | [diff] [blame] | 514 | break; | 
|  | 515 | /* Performance Monitor Overflow */ | 
|  | 516 | case (SEQSTAT_HWERRCAUSE_PERF_FLOW): | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 517 | verbose_printk(KERN_NOTICE HWC_x12(KERN_NOTICE)); | 
| Robin Getz | 13fe24f | 2008-01-27 15:38:56 +0800 | [diff] [blame] | 518 | break; | 
|  | 519 | /* RAISE 5 instruction */ | 
|  | 520 | case (SEQSTAT_HWERRCAUSE_RAISE_5): | 
|  | 521 | printk(KERN_NOTICE HWC_x18(KERN_NOTICE)); | 
|  | 522 | break; | 
|  | 523 | default:        /* Reserved */ | 
|  | 524 | printk(KERN_NOTICE HWC_default(KERN_NOTICE)); | 
|  | 525 | break; | 
|  | 526 | } | 
| Sonic Zhang | a5ac012 | 2008-10-13 14:07:19 +0800 | [diff] [blame] | 527 | CHK_DEBUGGER_TRAP_MAYBE(); | 
| Robin Getz | 13fe24f | 2008-01-27 15:38:56 +0800 | [diff] [blame] | 528 | break; | 
| Robin Getz | 5c64e0d | 2008-10-08 14:43:47 +0800 | [diff] [blame] | 529 | /* | 
|  | 530 | * We should be handling all known exception types above, | 
|  | 531 | * if we get here we hit a reserved one, so panic | 
|  | 532 | */ | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 533 | default: | 
| Robin Getz | 5c64e0d | 2008-10-08 14:43:47 +0800 | [diff] [blame] | 534 | oops_in_progress = 1; | 
|  | 535 | info.si_code = ILL_ILLPARAOP; | 
|  | 536 | sig = SIGILL; | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 537 | verbose_printk(KERN_EMERG "Caught Unhandled Exception, code = %08lx\n", | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 538 | (fp->seqstat & SEQSTAT_EXCAUSE)); | 
| Sonic Zhang | a5ac012 | 2008-10-13 14:07:19 +0800 | [diff] [blame] | 539 | CHK_DEBUGGER_TRAP_MAYBE(); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 540 | break; | 
|  | 541 | } | 
|  | 542 |  | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 543 | BUG_ON(sig == 0); | 
|  | 544 |  | 
|  | 545 | if (sig != SIGTRAP) { | 
| Mike Frysinger | 49dce91 | 2007-11-21 16:46:49 +0800 | [diff] [blame] | 546 | dump_bfin_process(fp); | 
| Robin Getz | b03b08b | 2007-12-23 22:57:01 +0800 | [diff] [blame] | 547 | dump_bfin_mem(fp); | 
| Mike Frysinger | 49dce91 | 2007-11-21 16:46:49 +0800 | [diff] [blame] | 548 | show_regs(fp); | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 549 |  | 
|  | 550 | /* Print out the trace buffer if it makes sense */ | 
|  | 551 | #ifndef CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE | 
|  | 552 | if (trapnr == VEC_CPLB_I_M || trapnr == VEC_CPLB_M) | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 553 | verbose_printk(KERN_NOTICE "No trace since you do not have " | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 554 | "CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE enabled\n" | 
|  | 555 | KERN_NOTICE "\n"); | 
|  | 556 | else | 
|  | 557 | #endif | 
|  | 558 | dump_bfin_trace_buffer(); | 
| Robin Getz | f09630b | 2008-07-26 19:45:46 +0800 | [diff] [blame] | 559 |  | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 560 | if (oops_in_progress) { | 
| Robin Getz | f09630b | 2008-07-26 19:45:46 +0800 | [diff] [blame] | 561 | /* Dump the current kernel stack */ | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 562 | verbose_printk(KERN_NOTICE "\n" KERN_NOTICE "Kernel Stack\n"); | 
| Robin Getz | f09630b | 2008-07-26 19:45:46 +0800 | [diff] [blame] | 563 | show_stack(current, NULL); | 
| Robin Getz | aee3a29 | 2008-01-11 16:53:00 +0800 | [diff] [blame] | 564 | print_modules(); | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 565 | #ifndef CONFIG_ACCESS_CHECK | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 566 | verbose_printk(KERN_EMERG "Please turn on " | 
| Robin Getz | 90c7f46 | 2007-11-18 00:35:33 +0800 | [diff] [blame] | 567 | "CONFIG_ACCESS_CHECK\n"); | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 568 | #endif | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 569 | panic("Kernel exception"); | 
| Robin Getz | f09630b | 2008-07-26 19:45:46 +0800 | [diff] [blame] | 570 | } else { | 
| Robin Getz | 4ee1c45 | 2008-10-28 11:36:11 +0800 | [diff] [blame] | 571 | #ifdef CONFIG_DEBUG_VERBOSE | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 572 | unsigned long *stack; | 
| Robin Getz | f09630b | 2008-07-26 19:45:46 +0800 | [diff] [blame] | 573 | /* Dump the user space stack */ | 
|  | 574 | stack = (unsigned long *)rdusp(); | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 575 | verbose_printk(KERN_NOTICE "Userspace Stack\n"); | 
| Robin Getz | f09630b | 2008-07-26 19:45:46 +0800 | [diff] [blame] | 576 | show_stack(NULL, stack); | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 577 | #endif | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 578 | } | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 579 | } | 
| Robin Getz | fb32291 | 2007-11-21 16:38:05 +0800 | [diff] [blame] | 580 |  | 
| Yi Li | 6a01f23 | 2009-01-07 23:14:39 +0800 | [diff] [blame] | 581 | #ifdef CONFIG_IPIPE | 
|  | 582 | if (!ipipe_trap_notify(fp->seqstat & 0x3f, fp)) | 
|  | 583 | #endif | 
|  | 584 | { | 
|  | 585 | info.si_signo = sig; | 
|  | 586 | info.si_errno = 0; | 
|  | 587 | info.si_addr = (void __user *)fp->pc; | 
|  | 588 | force_sig_info(sig, &info, current); | 
|  | 589 | } | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 590 |  | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 591 | trace_buffer_restore(j); | 
|  | 592 | return; | 
|  | 593 | } | 
|  | 594 |  | 
|  | 595 | /* Typical exception handling routines	*/ | 
|  | 596 |  | 
| Robin Getz | 518039b | 2007-07-25 11:03:28 +0800 | [diff] [blame] | 597 | #define EXPAND_LEN ((1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN) * 256 - 1) | 
|  | 598 |  | 
| Robin Getz | f09630b | 2008-07-26 19:45:46 +0800 | [diff] [blame] | 599 | /* | 
|  | 600 | * Similar to get_user, do some address checking, then dereference | 
|  | 601 | * Return true on sucess, false on bad address | 
|  | 602 | */ | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 603 | static bool get_instruction(unsigned short *val, unsigned short *address) | 
| Robin Getz | f09630b | 2008-07-26 19:45:46 +0800 | [diff] [blame] | 604 | { | 
|  | 605 |  | 
|  | 606 | unsigned long addr; | 
|  | 607 |  | 
|  | 608 | addr = (unsigned long)address; | 
|  | 609 |  | 
|  | 610 | /* Check for odd addresses */ | 
|  | 611 | if (addr & 0x1) | 
|  | 612 | return false; | 
|  | 613 |  | 
|  | 614 | /* Check that things do not wrap around */ | 
|  | 615 | if (addr > (addr + 2)) | 
|  | 616 | return false; | 
|  | 617 |  | 
|  | 618 | /* | 
|  | 619 | * Since we are in exception context, we need to do a little address checking | 
|  | 620 | * We need to make sure we are only accessing valid memory, and | 
|  | 621 | * we don't read something in the async space that can hang forever | 
|  | 622 | */ | 
|  | 623 | if ((addr >= FIXED_CODE_START && (addr + 2) <= physical_mem_end) || | 
| Mike Frysinger | 07aa7be | 2008-08-13 16:16:11 +0800 | [diff] [blame] | 624 | #if L2_LENGTH != 0 | 
| Robin Getz | f09630b | 2008-07-26 19:45:46 +0800 | [diff] [blame] | 625 | (addr >= L2_START && (addr + 2) <= (L2_START + L2_LENGTH)) || | 
|  | 626 | #endif | 
|  | 627 | (addr >= BOOT_ROM_START && (addr + 2) <= (BOOT_ROM_START + BOOT_ROM_LENGTH)) || | 
|  | 628 | #if L1_DATA_A_LENGTH != 0 | 
|  | 629 | (addr >= L1_DATA_A_START && (addr + 2) <= (L1_DATA_A_START + L1_DATA_A_LENGTH)) || | 
|  | 630 | #endif | 
|  | 631 | #if L1_DATA_B_LENGTH != 0 | 
|  | 632 | (addr >= L1_DATA_B_START && (addr + 2) <= (L1_DATA_B_START + L1_DATA_B_LENGTH)) || | 
|  | 633 | #endif | 
|  | 634 | (addr >= L1_SCRATCH_START && (addr + 2) <= (L1_SCRATCH_START + L1_SCRATCH_LENGTH)) || | 
|  | 635 | (!(bfin_read_EBIU_AMBCTL0() & B0RDYEN) && | 
|  | 636 | addr >= ASYNC_BANK0_BASE && (addr + 2) <= (ASYNC_BANK0_BASE + ASYNC_BANK0_SIZE)) || | 
|  | 637 | (!(bfin_read_EBIU_AMBCTL0() & B1RDYEN) && | 
|  | 638 | addr >= ASYNC_BANK1_BASE && (addr + 2) <= (ASYNC_BANK1_BASE + ASYNC_BANK1_SIZE)) || | 
|  | 639 | (!(bfin_read_EBIU_AMBCTL1() & B2RDYEN) && | 
|  | 640 | addr >= ASYNC_BANK2_BASE && (addr + 2) <= (ASYNC_BANK2_BASE + ASYNC_BANK1_SIZE)) || | 
|  | 641 | (!(bfin_read_EBIU_AMBCTL1() & B3RDYEN) && | 
|  | 642 | addr >= ASYNC_BANK3_BASE && (addr + 2) <= (ASYNC_BANK3_BASE + ASYNC_BANK1_SIZE))) { | 
|  | 643 | *val = *address; | 
|  | 644 | return true; | 
|  | 645 | } | 
|  | 646 |  | 
|  | 647 | #if L1_CODE_LENGTH != 0 | 
|  | 648 | if (addr >= L1_CODE_START && (addr + 2) <= (L1_CODE_START + L1_CODE_LENGTH)) { | 
| Robin Getz | 9df1028 | 2008-10-08 18:03:33 +0800 | [diff] [blame] | 649 | isram_memcpy(val, address, 2); | 
| Robin Getz | f09630b | 2008-07-26 19:45:46 +0800 | [diff] [blame] | 650 | return true; | 
|  | 651 | } | 
|  | 652 | #endif | 
|  | 653 |  | 
|  | 654 |  | 
|  | 655 | return false; | 
|  | 656 | } | 
|  | 657 |  | 
| Mike Frysinger | 36f649a | 2008-11-18 17:48:22 +0800 | [diff] [blame] | 658 | /* | 
| Robin Getz | d3d0ac2 | 2008-08-06 17:49:27 +0800 | [diff] [blame] | 659 | * decode the instruction if we are printing out the trace, as it | 
|  | 660 | * makes things easier to follow, without running it through objdump | 
|  | 661 | * These are the normal instructions which cause change of flow, which | 
|  | 662 | * would be at the source of the trace buffer | 
|  | 663 | */ | 
| Mike Frysinger | 36f649a | 2008-11-18 17:48:22 +0800 | [diff] [blame] | 664 | #if defined(CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_BFIN_HWTRACE_ON) | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 665 | static void decode_instruction(unsigned short *address) | 
| Robin Getz | d3d0ac2 | 2008-08-06 17:49:27 +0800 | [diff] [blame] | 666 | { | 
|  | 667 | unsigned short opcode; | 
|  | 668 |  | 
|  | 669 | if (get_instruction(&opcode, address)) { | 
|  | 670 | if (opcode == 0x0010) | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 671 | verbose_printk("RTS"); | 
| Robin Getz | d3d0ac2 | 2008-08-06 17:49:27 +0800 | [diff] [blame] | 672 | else if (opcode == 0x0011) | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 673 | verbose_printk("RTI"); | 
| Robin Getz | d3d0ac2 | 2008-08-06 17:49:27 +0800 | [diff] [blame] | 674 | else if (opcode == 0x0012) | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 675 | verbose_printk("RTX"); | 
| Robin Getz | 0be5893 | 2009-02-04 16:49:45 +0800 | [diff] [blame] | 676 | else if (opcode == 0x0013) | 
|  | 677 | verbose_printk("RTN"); | 
|  | 678 | else if (opcode == 0x0014) | 
|  | 679 | verbose_printk("RTE"); | 
|  | 680 | else if (opcode == 0x0025) | 
|  | 681 | verbose_printk("EMUEXCPT"); | 
|  | 682 | else if (opcode == 0x0040 && opcode <= 0x0047) | 
|  | 683 | verbose_printk("STI R%i", opcode & 7); | 
| Robin Getz | d3d0ac2 | 2008-08-06 17:49:27 +0800 | [diff] [blame] | 684 | else if (opcode >= 0x0050 && opcode <= 0x0057) | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 685 | verbose_printk("JUMP (P%i)", opcode & 7); | 
| Robin Getz | d3d0ac2 | 2008-08-06 17:49:27 +0800 | [diff] [blame] | 686 | else if (opcode >= 0x0060 && opcode <= 0x0067) | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 687 | verbose_printk("CALL (P%i)", opcode & 7); | 
| Robin Getz | d3d0ac2 | 2008-08-06 17:49:27 +0800 | [diff] [blame] | 688 | else if (opcode >= 0x0070 && opcode <= 0x0077) | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 689 | verbose_printk("CALL (PC+P%i)", opcode & 7); | 
| Robin Getz | d3d0ac2 | 2008-08-06 17:49:27 +0800 | [diff] [blame] | 690 | else if (opcode >= 0x0080 && opcode <= 0x0087) | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 691 | verbose_printk("JUMP (PC+P%i)", opcode & 7); | 
| Robin Getz | 0be5893 | 2009-02-04 16:49:45 +0800 | [diff] [blame] | 692 | else if (opcode >= 0x0090 && opcode <= 0x009F) | 
|  | 693 | verbose_printk("RAISE 0x%x", opcode & 0xF); | 
|  | 694 | else if (opcode >= 0x00A0 && opcode <= 0x00AF) | 
|  | 695 | verbose_printk("EXCPT 0x%x", opcode & 0xF); | 
| Robin Getz | d3d0ac2 | 2008-08-06 17:49:27 +0800 | [diff] [blame] | 696 | else if ((opcode >= 0x1000 && opcode <= 0x13FF) || (opcode >= 0x1800 && opcode <= 0x1BFF)) | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 697 | verbose_printk("IF !CC JUMP"); | 
| Robin Getz | d3d0ac2 | 2008-08-06 17:49:27 +0800 | [diff] [blame] | 698 | else if ((opcode >= 0x1400 && opcode <= 0x17ff) || (opcode >= 0x1c00 && opcode <= 0x1fff)) | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 699 | verbose_printk("IF CC JUMP"); | 
| Robin Getz | d3d0ac2 | 2008-08-06 17:49:27 +0800 | [diff] [blame] | 700 | else if (opcode >= 0x2000 && opcode <= 0x2fff) | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 701 | verbose_printk("JUMP.S"); | 
| Robin Getz | d3d0ac2 | 2008-08-06 17:49:27 +0800 | [diff] [blame] | 702 | else if (opcode >= 0xe080 && opcode <= 0xe0ff) | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 703 | verbose_printk("LSETUP"); | 
| Robin Getz | d3d0ac2 | 2008-08-06 17:49:27 +0800 | [diff] [blame] | 704 | else if (opcode >= 0xe200 && opcode <= 0xe2ff) | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 705 | verbose_printk("JUMP.L"); | 
| Robin Getz | d3d0ac2 | 2008-08-06 17:49:27 +0800 | [diff] [blame] | 706 | else if (opcode >= 0xe300 && opcode <= 0xe3ff) | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 707 | verbose_printk("CALL pcrel"); | 
| Robin Getz | d3d0ac2 | 2008-08-06 17:49:27 +0800 | [diff] [blame] | 708 | else | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 709 | verbose_printk("0x%04x", opcode); | 
| Robin Getz | d3d0ac2 | 2008-08-06 17:49:27 +0800 | [diff] [blame] | 710 | } | 
|  | 711 |  | 
|  | 712 | } | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 713 | #endif | 
| Robin Getz | d3d0ac2 | 2008-08-06 17:49:27 +0800 | [diff] [blame] | 714 |  | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 715 | void dump_bfin_trace_buffer(void) | 
|  | 716 | { | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 717 | #ifdef CONFIG_DEBUG_VERBOSE | 
| Robin Getz | 518039b | 2007-07-25 11:03:28 +0800 | [diff] [blame] | 718 | #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON | 
|  | 719 | int tflags, i = 0; | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 720 | char buf[150]; | 
| Robin Getz | d3d0ac2 | 2008-08-06 17:49:27 +0800 | [diff] [blame] | 721 | unsigned short *addr; | 
| Robin Getz | 518039b | 2007-07-25 11:03:28 +0800 | [diff] [blame] | 722 | #ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND | 
|  | 723 | int j, index; | 
|  | 724 | #endif | 
|  | 725 |  | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 726 | trace_buffer_save(tflags); | 
|  | 727 |  | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 728 | printk(KERN_NOTICE "Hardware Trace:\n"); | 
| Robin Getz | 518039b | 2007-07-25 11:03:28 +0800 | [diff] [blame] | 729 |  | 
| Robin Getz | d3d0ac2 | 2008-08-06 17:49:27 +0800 | [diff] [blame] | 730 | #ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND | 
|  | 731 | printk(KERN_NOTICE "WARNING: Expanded trace turned on - can not trace exceptions\n"); | 
|  | 732 | #endif | 
|  | 733 |  | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 734 | if (likely(bfin_read_TBUFSTAT() & TBUFCNT)) { | 
| Robin Getz | 518039b | 2007-07-25 11:03:28 +0800 | [diff] [blame] | 735 | for (; bfin_read_TBUFSTAT() & TBUFCNT; i++) { | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 736 | decode_address(buf, (unsigned long)bfin_read_TBUF()); | 
|  | 737 | printk(KERN_NOTICE "%4i Target : %s\n", i, buf); | 
| Robin Getz | f09630b | 2008-07-26 19:45:46 +0800 | [diff] [blame] | 738 | addr = (unsigned short *)bfin_read_TBUF(); | 
|  | 739 | decode_address(buf, (unsigned long)addr); | 
|  | 740 | printk(KERN_NOTICE "     Source : %s ", buf); | 
| Robin Getz | d3d0ac2 | 2008-08-06 17:49:27 +0800 | [diff] [blame] | 741 | decode_instruction(addr); | 
| Robin Getz | f09630b | 2008-07-26 19:45:46 +0800 | [diff] [blame] | 742 | printk("\n"); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 743 | } | 
|  | 744 | } | 
|  | 745 |  | 
| Robin Getz | 518039b | 2007-07-25 11:03:28 +0800 | [diff] [blame] | 746 | #ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND | 
|  | 747 | if (trace_buff_offset) | 
| Robin Getz | d3d0ac2 | 2008-08-06 17:49:27 +0800 | [diff] [blame] | 748 | index = trace_buff_offset / 4; | 
| Robin Getz | 518039b | 2007-07-25 11:03:28 +0800 | [diff] [blame] | 749 | else | 
|  | 750 | index = EXPAND_LEN; | 
|  | 751 |  | 
|  | 752 | j = (1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN) * 128; | 
|  | 753 | while (j) { | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 754 | decode_address(buf, software_trace_buff[index]); | 
|  | 755 | printk(KERN_NOTICE "%4i Target : %s\n", i, buf); | 
| Robin Getz | 518039b | 2007-07-25 11:03:28 +0800 | [diff] [blame] | 756 | index -= 1; | 
|  | 757 | if (index < 0 ) | 
|  | 758 | index = EXPAND_LEN; | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 759 | decode_address(buf, software_trace_buff[index]); | 
| Robin Getz | d3d0ac2 | 2008-08-06 17:49:27 +0800 | [diff] [blame] | 760 | printk(KERN_NOTICE "     Source : %s ", buf); | 
|  | 761 | decode_instruction((unsigned short *)software_trace_buff[index]); | 
|  | 762 | printk("\n"); | 
| Robin Getz | 518039b | 2007-07-25 11:03:28 +0800 | [diff] [blame] | 763 | index -= 1; | 
|  | 764 | if (index < 0) | 
|  | 765 | index = EXPAND_LEN; | 
| Robin Getz | 518039b | 2007-07-25 11:03:28 +0800 | [diff] [blame] | 766 | j--; | 
|  | 767 | i++; | 
|  | 768 | } | 
|  | 769 | #endif | 
|  | 770 |  | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 771 | trace_buffer_restore(tflags); | 
| Robin Getz | 518039b | 2007-07-25 11:03:28 +0800 | [diff] [blame] | 772 | #endif | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 773 | #endif | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 774 | } | 
|  | 775 | EXPORT_SYMBOL(dump_bfin_trace_buffer); | 
|  | 776 |  | 
| Robin Getz | f09630b | 2008-07-26 19:45:46 +0800 | [diff] [blame] | 777 | /* | 
|  | 778 | * Checks to see if the address pointed to is either a | 
|  | 779 | * 16-bit CALL instruction, or a 32-bit CALL instruction | 
|  | 780 | */ | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 781 | static bool is_bfin_call(unsigned short *addr) | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 782 | { | 
| Robin Getz | f09630b | 2008-07-26 19:45:46 +0800 | [diff] [blame] | 783 | unsigned short opcode = 0, *ins_addr; | 
|  | 784 | ins_addr = (unsigned short *)addr; | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 785 |  | 
| Robin Getz | f09630b | 2008-07-26 19:45:46 +0800 | [diff] [blame] | 786 | if (!get_instruction(&opcode, ins_addr)) | 
|  | 787 | return false; | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 788 |  | 
| Robin Getz | f09630b | 2008-07-26 19:45:46 +0800 | [diff] [blame] | 789 | if ((opcode >= 0x0060 && opcode <= 0x0067) || | 
|  | 790 | (opcode >= 0x0070 && opcode <= 0x0077)) | 
|  | 791 | return true; | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 792 |  | 
| Robin Getz | f09630b | 2008-07-26 19:45:46 +0800 | [diff] [blame] | 793 | ins_addr--; | 
|  | 794 | if (!get_instruction(&opcode, ins_addr)) | 
|  | 795 | return false; | 
|  | 796 |  | 
|  | 797 | if (opcode >= 0xE300 && opcode <= 0xE3FF) | 
|  | 798 | return true; | 
|  | 799 |  | 
|  | 800 | return false; | 
|  | 801 |  | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 802 | } | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 803 |  | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 804 | void show_stack(struct task_struct *task, unsigned long *stack) | 
|  | 805 | { | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 806 | #ifdef CONFIG_PRINTK | 
| Robin Getz | f09630b | 2008-07-26 19:45:46 +0800 | [diff] [blame] | 807 | unsigned int *addr, *endstack, *fp = 0, *frame; | 
|  | 808 | unsigned short *ins_addr; | 
|  | 809 | char buf[150]; | 
|  | 810 | unsigned int i, j, ret_addr, frame_no = 0; | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 811 |  | 
| Robin Getz | f09630b | 2008-07-26 19:45:46 +0800 | [diff] [blame] | 812 | /* | 
|  | 813 | * If we have been passed a specific stack, use that one otherwise | 
|  | 814 | *    if we have been passed a task structure, use that, otherwise | 
|  | 815 | *    use the stack of where the variable "stack" exists | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 816 | */ | 
|  | 817 |  | 
| Robin Getz | f09630b | 2008-07-26 19:45:46 +0800 | [diff] [blame] | 818 | if (stack == NULL) { | 
|  | 819 | if (task) { | 
|  | 820 | /* We know this is a kernel stack, so this is the start/end */ | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 821 | stack = (unsigned long *)task->thread.ksp; | 
| Robin Getz | f09630b | 2008-07-26 19:45:46 +0800 | [diff] [blame] | 822 | endstack = (unsigned int *)(((unsigned int)(stack) & ~(THREAD_SIZE - 1)) + THREAD_SIZE); | 
|  | 823 | } else { | 
|  | 824 | /* print out the existing stack info */ | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 825 | stack = (unsigned long *)&stack; | 
| Robin Getz | f09630b | 2008-07-26 19:45:46 +0800 | [diff] [blame] | 826 | endstack = (unsigned int *)PAGE_ALIGN((unsigned int)stack); | 
|  | 827 | } | 
|  | 828 | } else | 
|  | 829 | endstack = (unsigned int *)PAGE_ALIGN((unsigned int)stack); | 
|  | 830 |  | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 831 | printk(KERN_NOTICE "Stack info:\n"); | 
| Robin Getz | f09630b | 2008-07-26 19:45:46 +0800 | [diff] [blame] | 832 | decode_address(buf, (unsigned int)stack); | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 833 | printk(KERN_NOTICE " SP: [0x%p] %s\n", stack, buf); | 
|  | 834 |  | 
| Robin Getz | f09630b | 2008-07-26 19:45:46 +0800 | [diff] [blame] | 835 | /* First thing is to look for a frame pointer */ | 
| Jie Zhang | 881eb62 | 2009-02-04 16:49:45 +0800 | [diff] [blame] | 836 | for (addr = (unsigned int *)((unsigned int)stack & ~0xF); addr < endstack; addr++) { | 
| Robin Getz | f09630b | 2008-07-26 19:45:46 +0800 | [diff] [blame] | 837 | if (*addr & 0x1) | 
|  | 838 | continue; | 
|  | 839 | ins_addr = (unsigned short *)*addr; | 
|  | 840 | ins_addr--; | 
|  | 841 | if (is_bfin_call(ins_addr)) | 
|  | 842 | fp = addr - 1; | 
|  | 843 |  | 
|  | 844 | if (fp) { | 
|  | 845 | /* Let's check to see if it is a frame pointer */ | 
| Jie Zhang | 881eb62 | 2009-02-04 16:49:45 +0800 | [diff] [blame] | 846 | while (fp >= (addr - 1) && fp < endstack | 
|  | 847 | && fp && ((unsigned int) fp & 0x3) == 0) | 
| Robin Getz | f09630b | 2008-07-26 19:45:46 +0800 | [diff] [blame] | 848 | fp = (unsigned int *)*fp; | 
|  | 849 | if (fp == 0 || fp == endstack) { | 
|  | 850 | fp = addr - 1; | 
|  | 851 | break; | 
|  | 852 | } | 
|  | 853 | fp = 0; | 
|  | 854 | } | 
|  | 855 | } | 
|  | 856 | if (fp) { | 
|  | 857 | frame = fp; | 
| Jie Zhang | b339dc7 | 2009-01-07 23:14:39 +0800 | [diff] [blame] | 858 | printk(KERN_NOTICE " FP: (0x%p)\n", fp); | 
| Robin Getz | f09630b | 2008-07-26 19:45:46 +0800 | [diff] [blame] | 859 | } else | 
|  | 860 | frame = 0; | 
|  | 861 |  | 
|  | 862 | /* | 
|  | 863 | * Now that we think we know where things are, we | 
|  | 864 | * walk the stack again, this time printing things out | 
|  | 865 | * incase there is no frame pointer, we still look for | 
|  | 866 | * valid return addresses | 
|  | 867 | */ | 
|  | 868 |  | 
|  | 869 | /* First time print out data, next time, print out symbols */ | 
|  | 870 | for (j = 0; j <= 1; j++) { | 
|  | 871 | if (j) | 
|  | 872 | printk(KERN_NOTICE "Return addresses in stack:\n"); | 
|  | 873 | else | 
|  | 874 | printk(KERN_NOTICE " Memory from 0x%08lx to %p", ((long unsigned int)stack & ~0xF), endstack); | 
|  | 875 |  | 
|  | 876 | fp = frame; | 
|  | 877 | frame_no = 0; | 
|  | 878 |  | 
|  | 879 | for (addr = (unsigned int *)((unsigned int)stack & ~0xF), i = 0; | 
|  | 880 | addr <= endstack; addr++, i++) { | 
|  | 881 |  | 
|  | 882 | ret_addr = 0; | 
|  | 883 | if (!j && i % 8 == 0) | 
|  | 884 | printk("\n" KERN_NOTICE "%p:",addr); | 
|  | 885 |  | 
|  | 886 | /* if it is an odd address, or zero, just skip it */ | 
|  | 887 | if (*addr & 0x1 || !*addr) | 
|  | 888 | goto print; | 
|  | 889 |  | 
|  | 890 | ins_addr = (unsigned short *)*addr; | 
|  | 891 |  | 
|  | 892 | /* Go back one instruction, and see if it is a CALL */ | 
|  | 893 | ins_addr--; | 
|  | 894 | ret_addr = is_bfin_call(ins_addr); | 
|  | 895 | print: | 
|  | 896 | if (!j && stack == (unsigned long *)addr) | 
|  | 897 | printk("[%08x]", *addr); | 
|  | 898 | else if (ret_addr) | 
|  | 899 | if (j) { | 
|  | 900 | decode_address(buf, (unsigned int)*addr); | 
|  | 901 | if (frame == addr) { | 
|  | 902 | printk(KERN_NOTICE "   frame %2i : %s\n", frame_no, buf); | 
|  | 903 | continue; | 
|  | 904 | } | 
|  | 905 | printk(KERN_NOTICE "    address : %s\n", buf); | 
|  | 906 | } else | 
|  | 907 | printk("<%08x>", *addr); | 
|  | 908 | else if (fp == addr) { | 
|  | 909 | if (j) | 
|  | 910 | frame = addr+1; | 
|  | 911 | else | 
|  | 912 | printk("(%08x)", *addr); | 
|  | 913 |  | 
|  | 914 | fp = (unsigned int *)*addr; | 
|  | 915 | frame_no++; | 
|  | 916 |  | 
|  | 917 | } else if (!j) | 
|  | 918 | printk(" %08x ", *addr); | 
|  | 919 | } | 
|  | 920 | if (!j) | 
|  | 921 | printk("\n"); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 922 | } | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 923 | #endif | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 924 | } | 
|  | 925 |  | 
|  | 926 | void dump_stack(void) | 
|  | 927 | { | 
|  | 928 | unsigned long stack; | 
| Robin Getz | 518039b | 2007-07-25 11:03:28 +0800 | [diff] [blame] | 929 | #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 930 | int tflags; | 
| Robin Getz | 518039b | 2007-07-25 11:03:28 +0800 | [diff] [blame] | 931 | #endif | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 932 | trace_buffer_save(tflags); | 
|  | 933 | dump_bfin_trace_buffer(); | 
|  | 934 | show_stack(current, &stack); | 
|  | 935 | trace_buffer_restore(tflags); | 
|  | 936 | } | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 937 | EXPORT_SYMBOL(dump_stack); | 
|  | 938 |  | 
| Mike Frysinger | 49dce91 | 2007-11-21 16:46:49 +0800 | [diff] [blame] | 939 | void dump_bfin_process(struct pt_regs *fp) | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 940 | { | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 941 | #ifdef CONFIG_DEBUG_VERBOSE | 
| Mike Frysinger | 49dce91 | 2007-11-21 16:46:49 +0800 | [diff] [blame] | 942 | /* We should be able to look at fp->ipend, but we don't push it on the | 
|  | 943 | * stack all the time, so do this until we fix that */ | 
|  | 944 | unsigned int context = bfin_read_IPEND(); | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 945 |  | 
| Mike Frysinger | 49dce91 | 2007-11-21 16:46:49 +0800 | [diff] [blame] | 946 | if (oops_in_progress) | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 947 | verbose_printk(KERN_EMERG "Kernel OOPS in progress\n"); | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 948 |  | 
| Robin Getz | b03b08b | 2007-12-23 22:57:01 +0800 | [diff] [blame] | 949 | if (context & 0x0020 && (fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR) | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 950 | verbose_printk(KERN_NOTICE "HW Error context\n"); | 
| Robin Getz | b03b08b | 2007-12-23 22:57:01 +0800 | [diff] [blame] | 951 | else if (context & 0x0020) | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 952 | verbose_printk(KERN_NOTICE "Deferred Exception context\n"); | 
| Mike Frysinger | 49dce91 | 2007-11-21 16:46:49 +0800 | [diff] [blame] | 953 | else if (context & 0x3FC0) | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 954 | verbose_printk(KERN_NOTICE "Interrupt context\n"); | 
| Mike Frysinger | 49dce91 | 2007-11-21 16:46:49 +0800 | [diff] [blame] | 955 | else if (context & 0x4000) | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 956 | verbose_printk(KERN_NOTICE "Deferred Interrupt context\n"); | 
| Mike Frysinger | 49dce91 | 2007-11-21 16:46:49 +0800 | [diff] [blame] | 957 | else if (context & 0x8000) | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 958 | verbose_printk(KERN_NOTICE "Kernel process context\n"); | 
| Mike Frysinger | 49dce91 | 2007-11-21 16:46:49 +0800 | [diff] [blame] | 959 |  | 
| Robin Getz | 9a62ca4 | 2008-03-26 09:15:58 +0800 | [diff] [blame] | 960 | /* Because we are crashing, and pointers could be bad, we check things | 
|  | 961 | * pretty closely before we use them | 
|  | 962 | */ | 
| Robin Getz | 7f1c906 | 2008-04-25 03:36:31 +0800 | [diff] [blame] | 963 | if ((unsigned long)current >= FIXED_CODE_START && | 
|  | 964 | !((unsigned long)current & 0x3) && current->pid) { | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 965 | verbose_printk(KERN_NOTICE "CURRENT PROCESS:\n"); | 
| Robin Getz | 9a62ca4 | 2008-03-26 09:15:58 +0800 | [diff] [blame] | 966 | if (current->comm >= (char *)FIXED_CODE_START) | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 967 | verbose_printk(KERN_NOTICE "COMM=%s PID=%d\n", | 
| Robin Getz | 9a62ca4 | 2008-03-26 09:15:58 +0800 | [diff] [blame] | 968 | current->comm, current->pid); | 
|  | 969 | else | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 970 | verbose_printk(KERN_NOTICE "COMM= invalid\n"); | 
| Mike Frysinger | 49dce91 | 2007-11-21 16:46:49 +0800 | [diff] [blame] | 971 |  | 
| Graf Yang | 8f65873 | 2008-11-18 17:48:22 +0800 | [diff] [blame] | 972 | printk(KERN_NOTICE "CPU = %d\n", current_thread_info()->cpu); | 
| Robin Getz | 9a62ca4 | 2008-03-26 09:15:58 +0800 | [diff] [blame] | 973 | if (!((unsigned long)current->mm & 0x3) && (unsigned long)current->mm >= FIXED_CODE_START) | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 974 | verbose_printk(KERN_NOTICE  "TEXT = 0x%p-0x%p        DATA = 0x%p-0x%p\n" | 
| Robin Getz | 9a62ca4 | 2008-03-26 09:15:58 +0800 | [diff] [blame] | 975 | KERN_NOTICE " BSS = 0x%p-0x%p  USER-STACK = 0x%p\n" | 
|  | 976 | KERN_NOTICE "\n", | 
|  | 977 | (void *)current->mm->start_code, | 
|  | 978 | (void *)current->mm->end_code, | 
|  | 979 | (void *)current->mm->start_data, | 
|  | 980 | (void *)current->mm->end_data, | 
|  | 981 | (void *)current->mm->end_data, | 
|  | 982 | (void *)current->mm->brk, | 
|  | 983 | (void *)current->mm->start_stack); | 
|  | 984 | else | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 985 | verbose_printk(KERN_NOTICE "invalid mm\n"); | 
| Mike Frysinger | 49dce91 | 2007-11-21 16:46:49 +0800 | [diff] [blame] | 986 | } else | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 987 | verbose_printk(KERN_NOTICE "\n" KERN_NOTICE | 
| Mike Frysinger | 49dce91 | 2007-11-21 16:46:49 +0800 | [diff] [blame] | 988 | "No Valid process in current context\n"); | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 989 | #endif | 
| Mike Frysinger | 49dce91 | 2007-11-21 16:46:49 +0800 | [diff] [blame] | 990 | } | 
|  | 991 |  | 
| Robin Getz | b03b08b | 2007-12-23 22:57:01 +0800 | [diff] [blame] | 992 | void dump_bfin_mem(struct pt_regs *fp) | 
| Mike Frysinger | 49dce91 | 2007-11-21 16:46:49 +0800 | [diff] [blame] | 993 | { | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 994 | #ifdef CONFIG_DEBUG_VERBOSE | 
| Robin Getz | b03b08b | 2007-12-23 22:57:01 +0800 | [diff] [blame] | 995 | unsigned short *addr, *erraddr, val = 0, err = 0; | 
|  | 996 | char sti = 0, buf[6]; | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 997 |  | 
| Bernd Schmidt | 5d750b9 | 2008-04-25 05:02:33 +0800 | [diff] [blame] | 998 | erraddr = (void *)fp->pc; | 
| Robin Getz | c5d88d9 | 2007-06-21 11:34:16 +0800 | [diff] [blame] | 999 |  | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 1000 | verbose_printk(KERN_NOTICE "return address: [0x%p]; contents of:", erraddr); | 
| Robin Getz | b03b08b | 2007-12-23 22:57:01 +0800 | [diff] [blame] | 1001 |  | 
|  | 1002 | for (addr = (unsigned short *)((unsigned long)erraddr & ~0xF) - 0x10; | 
|  | 1003 | addr < (unsigned short *)((unsigned long)erraddr & ~0xF) + 0x10; | 
|  | 1004 | addr++) { | 
|  | 1005 | if (!((unsigned long)addr & 0xF)) | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 1006 | verbose_printk("\n" KERN_NOTICE "0x%p: ", addr); | 
| Robin Getz | b03b08b | 2007-12-23 22:57:01 +0800 | [diff] [blame] | 1007 |  | 
| Robin Getz | 7d98c88 | 2008-10-08 16:29:01 +0800 | [diff] [blame] | 1008 | if (!get_instruction(&val, addr)) { | 
| Robin Getz | b03b08b | 2007-12-23 22:57:01 +0800 | [diff] [blame] | 1009 | val = 0; | 
|  | 1010 | sprintf(buf, "????"); | 
| Robin Getz | b03b08b | 2007-12-23 22:57:01 +0800 | [diff] [blame] | 1011 | } else | 
|  | 1012 | sprintf(buf, "%04x", val); | 
|  | 1013 |  | 
|  | 1014 | if (addr == erraddr) { | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 1015 | verbose_printk("[%s]", buf); | 
| Robin Getz | b03b08b | 2007-12-23 22:57:01 +0800 | [diff] [blame] | 1016 | err = val; | 
|  | 1017 | } else | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 1018 | verbose_printk(" %s ", buf); | 
| Robin Getz | b03b08b | 2007-12-23 22:57:01 +0800 | [diff] [blame] | 1019 |  | 
|  | 1020 | /* Do any previous instructions turn on interrupts? */ | 
|  | 1021 | if (addr <= erraddr &&				/* in the past */ | 
|  | 1022 | ((val >= 0x0040 && val <= 0x0047) ||	/* STI instruction */ | 
|  | 1023 | val == 0x017b))				/* [SP++] = RETI */ | 
|  | 1024 | sti = 1; | 
|  | 1025 | } | 
|  | 1026 |  | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 1027 | verbose_printk("\n"); | 
| Robin Getz | b03b08b | 2007-12-23 22:57:01 +0800 | [diff] [blame] | 1028 |  | 
|  | 1029 | /* Hardware error interrupts can be deferred */ | 
|  | 1030 | if (unlikely(sti && (fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR && | 
|  | 1031 | oops_in_progress)){ | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 1032 | verbose_printk(KERN_NOTICE "Looks like this was a deferred error - sorry\n"); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 1033 | #ifndef CONFIG_DEBUG_HWERR | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 1034 | verbose_printk(KERN_NOTICE "The remaining message may be meaningless\n" | 
| Robin Getz | b03b08b | 2007-12-23 22:57:01 +0800 | [diff] [blame] | 1035 | KERN_NOTICE "You should enable CONFIG_DEBUG_HWERR to get a" | 
|  | 1036 | " better idea where it came from\n"); | 
|  | 1037 | #else | 
|  | 1038 | /* If we are handling only one peripheral interrupt | 
|  | 1039 | * and current mm and pid are valid, and the last error | 
|  | 1040 | * was in that user space process's text area | 
|  | 1041 | * print it out - because that is where the problem exists | 
|  | 1042 | */ | 
|  | 1043 | if ((!(((fp)->ipend & ~0x30) & (((fp)->ipend & ~0x30) - 1))) && | 
|  | 1044 | (current->pid && current->mm)) { | 
|  | 1045 | /* And the last RETI points to the current userspace context */ | 
|  | 1046 | if ((fp + 1)->pc >= current->mm->start_code && | 
|  | 1047 | (fp + 1)->pc <= current->mm->end_code) { | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 1048 | verbose_printk(KERN_NOTICE "It might be better to look around here : \n"); | 
|  | 1049 | verbose_printk(KERN_NOTICE "-------------------------------------------\n"); | 
| Robin Getz | b03b08b | 2007-12-23 22:57:01 +0800 | [diff] [blame] | 1050 | show_regs(fp + 1); | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 1051 | verbose_printk(KERN_NOTICE "-------------------------------------------\n"); | 
| Robin Getz | b03b08b | 2007-12-23 22:57:01 +0800 | [diff] [blame] | 1052 | } | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 1053 | } | 
| Robin Getz | b03b08b | 2007-12-23 22:57:01 +0800 | [diff] [blame] | 1054 | #endif | 
|  | 1055 | } | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 1056 | #endif | 
| Mike Frysinger | 49dce91 | 2007-11-21 16:46:49 +0800 | [diff] [blame] | 1057 | } | 
|  | 1058 |  | 
|  | 1059 | void show_regs(struct pt_regs *fp) | 
|  | 1060 | { | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 1061 | #ifdef CONFIG_DEBUG_VERBOSE | 
| Mike Frysinger | 49dce91 | 2007-11-21 16:46:49 +0800 | [diff] [blame] | 1062 | char buf [150]; | 
| Robin Getz | d8f66c8 | 2007-12-24 15:27:56 +0800 | [diff] [blame] | 1063 | struct irqaction *action; | 
|  | 1064 | unsigned int i; | 
| Robin Getz | 2f95d5b | 2009-02-04 16:49:45 +0800 | [diff] [blame] | 1065 | unsigned long flags = 0; | 
| Graf Yang | 8f65873 | 2008-11-18 17:48:22 +0800 | [diff] [blame] | 1066 | unsigned int cpu = smp_processor_id(); | 
| Robin Getz | 2f95d5b | 2009-02-04 16:49:45 +0800 | [diff] [blame] | 1067 | unsigned char in_atomic = (bfin_read_IPEND() & 0x10) || in_atomic(); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 1068 |  | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 1069 | verbose_printk(KERN_NOTICE "\n" KERN_NOTICE "SEQUENCER STATUS:\t\t%s\n", print_tainted()); | 
|  | 1070 | verbose_printk(KERN_NOTICE " SEQSTAT: %08lx  IPEND: %04lx  SYSCFG: %04lx\n", | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 1071 | (long)fp->seqstat, fp->ipend, fp->syscfg); | 
| Robin Getz | 1d5ff7e | 2008-10-09 17:06:32 +0800 | [diff] [blame] | 1072 | if ((fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR) { | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 1073 | verbose_printk(KERN_NOTICE "  HWERRCAUSE: 0x%lx\n", | 
| Robin Getz | 1d5ff7e | 2008-10-09 17:06:32 +0800 | [diff] [blame] | 1074 | (fp->seqstat & SEQSTAT_HWERRCAUSE) >> 14); | 
|  | 1075 | #ifdef EBIU_ERRMST | 
|  | 1076 | /* If the error was from the EBIU, print it out */ | 
|  | 1077 | if (bfin_read_EBIU_ERRMST() & CORE_ERROR) { | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 1078 | verbose_printk(KERN_NOTICE "  EBIU Error Reason  : 0x%04x\n", | 
| Robin Getz | 1d5ff7e | 2008-10-09 17:06:32 +0800 | [diff] [blame] | 1079 | bfin_read_EBIU_ERRMST()); | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 1080 | verbose_printk(KERN_NOTICE "  EBIU Error Address : 0x%08x\n", | 
| Robin Getz | 1d5ff7e | 2008-10-09 17:06:32 +0800 | [diff] [blame] | 1081 | bfin_read_EBIU_ERRADD()); | 
|  | 1082 | } | 
|  | 1083 | #endif | 
|  | 1084 | } | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 1085 | verbose_printk(KERN_NOTICE "  EXCAUSE   : 0x%lx\n", | 
| Robin Getz | 13fe24f | 2008-01-27 15:38:56 +0800 | [diff] [blame] | 1086 | fp->seqstat & SEQSTAT_EXCAUSE); | 
| Robin Getz | 2f95d5b | 2009-02-04 16:49:45 +0800 | [diff] [blame] | 1087 | for (i = 2; i <= 15 ; i++) { | 
| Robin Getz | d8f66c8 | 2007-12-24 15:27:56 +0800 | [diff] [blame] | 1088 | if (fp->ipend & (1 << i)) { | 
| Robin Getz | 2f95d5b | 2009-02-04 16:49:45 +0800 | [diff] [blame] | 1089 | if (i != 4) { | 
|  | 1090 | decode_address(buf, bfin_read32(EVT0 + 4*i)); | 
|  | 1091 | verbose_printk(KERN_NOTICE "  physical IVG%i asserted : %s\n", i, buf); | 
|  | 1092 | } else | 
|  | 1093 | verbose_printk(KERN_NOTICE "  interrupts disabled\n"); | 
| Robin Getz | d8f66c8 | 2007-12-24 15:27:56 +0800 | [diff] [blame] | 1094 | } | 
|  | 1095 | } | 
|  | 1096 |  | 
|  | 1097 | /* if no interrupts are going off, don't print this out */ | 
|  | 1098 | if (fp->ipend & ~0x3F) { | 
|  | 1099 | for (i = 0; i < (NR_IRQS - 1); i++) { | 
| Robin Getz | 2f95d5b | 2009-02-04 16:49:45 +0800 | [diff] [blame] | 1100 | if (!in_atomic) | 
|  | 1101 | spin_lock_irqsave(&irq_desc[i].lock, flags); | 
|  | 1102 |  | 
| Robin Getz | d8f66c8 | 2007-12-24 15:27:56 +0800 | [diff] [blame] | 1103 | action = irq_desc[i].action; | 
|  | 1104 | if (!action) | 
|  | 1105 | goto unlock; | 
|  | 1106 |  | 
|  | 1107 | decode_address(buf, (unsigned int)action->handler); | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 1108 | verbose_printk(KERN_NOTICE "  logical irq %3d mapped  : %s", i, buf); | 
| Robin Getz | d8f66c8 | 2007-12-24 15:27:56 +0800 | [diff] [blame] | 1109 | for (action = action->next; action; action = action->next) { | 
|  | 1110 | decode_address(buf, (unsigned int)action->handler); | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 1111 | verbose_printk(", %s", buf); | 
| Robin Getz | d8f66c8 | 2007-12-24 15:27:56 +0800 | [diff] [blame] | 1112 | } | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 1113 | verbose_printk("\n"); | 
| Robin Getz | d8f66c8 | 2007-12-24 15:27:56 +0800 | [diff] [blame] | 1114 | unlock: | 
| Robin Getz | 2f95d5b | 2009-02-04 16:49:45 +0800 | [diff] [blame] | 1115 | if (!in_atomic) | 
|  | 1116 | spin_unlock_irqrestore(&irq_desc[i].lock, flags); | 
| Robin Getz | d8f66c8 | 2007-12-24 15:27:56 +0800 | [diff] [blame] | 1117 | } | 
|  | 1118 | } | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 1119 |  | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 1120 | decode_address(buf, fp->rete); | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 1121 | verbose_printk(KERN_NOTICE " RETE: %s\n", buf); | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 1122 | decode_address(buf, fp->retn); | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 1123 | verbose_printk(KERN_NOTICE " RETN: %s\n", buf); | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 1124 | decode_address(buf, fp->retx); | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 1125 | verbose_printk(KERN_NOTICE " RETX: %s\n", buf); | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 1126 | decode_address(buf, fp->rets); | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 1127 | verbose_printk(KERN_NOTICE " RETS: %s\n", buf); | 
| Mike Frysinger | 49dce91 | 2007-11-21 16:46:49 +0800 | [diff] [blame] | 1128 | decode_address(buf, fp->pc); | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 1129 | verbose_printk(KERN_NOTICE " PC  : %s\n", buf); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 1130 |  | 
| Robin Getz | 13fe24f | 2008-01-27 15:38:56 +0800 | [diff] [blame] | 1131 | if (((long)fp->seqstat &  SEQSTAT_EXCAUSE) && | 
|  | 1132 | (((long)fp->seqstat & SEQSTAT_EXCAUSE) != VEC_HWERR)) { | 
| Graf Yang | 8f65873 | 2008-11-18 17:48:22 +0800 | [diff] [blame] | 1133 | decode_address(buf, cpu_pda[cpu].dcplb_fault_addr); | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 1134 | verbose_printk(KERN_NOTICE "DCPLB_FAULT_ADDR: %s\n", buf); | 
| Graf Yang | 8f65873 | 2008-11-18 17:48:22 +0800 | [diff] [blame] | 1135 | decode_address(buf, cpu_pda[cpu].icplb_fault_addr); | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 1136 | verbose_printk(KERN_NOTICE "ICPLB_FAULT_ADDR: %s\n", buf); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 1137 | } | 
|  | 1138 |  | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 1139 | verbose_printk(KERN_NOTICE "\n" KERN_NOTICE "PROCESSOR STATE:\n"); | 
|  | 1140 | verbose_printk(KERN_NOTICE " R0 : %08lx    R1 : %08lx    R2 : %08lx    R3 : %08lx\n", | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 1141 | fp->r0, fp->r1, fp->r2, fp->r3); | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 1142 | verbose_printk(KERN_NOTICE " R4 : %08lx    R5 : %08lx    R6 : %08lx    R7 : %08lx\n", | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 1143 | fp->r4, fp->r5, fp->r6, fp->r7); | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 1144 | verbose_printk(KERN_NOTICE " P0 : %08lx    P1 : %08lx    P2 : %08lx    P3 : %08lx\n", | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 1145 | fp->p0, fp->p1, fp->p2, fp->p3); | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 1146 | verbose_printk(KERN_NOTICE " P4 : %08lx    P5 : %08lx    FP : %08lx    SP : %08lx\n", | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 1147 | fp->p4, fp->p5, fp->fp, (long)fp); | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 1148 | verbose_printk(KERN_NOTICE " LB0: %08lx    LT0: %08lx    LC0: %08lx\n", | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 1149 | fp->lb0, fp->lt0, fp->lc0); | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 1150 | verbose_printk(KERN_NOTICE " LB1: %08lx    LT1: %08lx    LC1: %08lx\n", | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 1151 | fp->lb1, fp->lt1, fp->lc1); | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 1152 | verbose_printk(KERN_NOTICE " B0 : %08lx    L0 : %08lx    M0 : %08lx    I0 : %08lx\n", | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 1153 | fp->b0, fp->l0, fp->m0, fp->i0); | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 1154 | verbose_printk(KERN_NOTICE " B1 : %08lx    L1 : %08lx    M1 : %08lx    I1 : %08lx\n", | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 1155 | fp->b1, fp->l1, fp->m1, fp->i1); | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 1156 | verbose_printk(KERN_NOTICE " B2 : %08lx    L2 : %08lx    M2 : %08lx    I2 : %08lx\n", | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 1157 | fp->b2, fp->l2, fp->m2, fp->i2); | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 1158 | verbose_printk(KERN_NOTICE " B3 : %08lx    L3 : %08lx    M3 : %08lx    I3 : %08lx\n", | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 1159 | fp->b3, fp->l3, fp->m3, fp->i3); | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 1160 | verbose_printk(KERN_NOTICE "A0.w: %08lx   A0.x: %08lx   A1.w: %08lx   A1.x: %08lx\n", | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 1161 | fp->a0w, fp->a0x, fp->a1w, fp->a1x); | 
|  | 1162 |  | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 1163 | verbose_printk(KERN_NOTICE "USP : %08lx  ASTAT: %08lx\n", | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 1164 | rdusp(), fp->astat); | 
|  | 1165 |  | 
| Robin Getz | 9f06c38 | 2008-10-10 18:13:21 +0800 | [diff] [blame] | 1166 | verbose_printk(KERN_NOTICE "\n"); | 
|  | 1167 | #endif | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 1168 | } | 
|  | 1169 |  | 
|  | 1170 | #ifdef CONFIG_SYS_BFIN_SPINLOCK_L1 | 
|  | 1171 | asmlinkage int sys_bfin_spinlock(int *spinlock)__attribute__((l1_text)); | 
|  | 1172 | #endif | 
|  | 1173 |  | 
| Graf Yang | 8f65873 | 2008-11-18 17:48:22 +0800 | [diff] [blame] | 1174 | static DEFINE_SPINLOCK(bfin_spinlock_lock); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 1175 |  | 
| Graf Yang | 8f65873 | 2008-11-18 17:48:22 +0800 | [diff] [blame] | 1176 | asmlinkage int sys_bfin_spinlock(int *p) | 
|  | 1177 | { | 
|  | 1178 | int ret, tmp = 0; | 
|  | 1179 |  | 
|  | 1180 | spin_lock(&bfin_spinlock_lock);	/* This would also hold kernel preemption. */ | 
|  | 1181 | ret = get_user(tmp, p); | 
|  | 1182 | if (likely(ret == 0)) { | 
|  | 1183 | if (unlikely(tmp)) | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 1184 | ret = 1; | 
| Graf Yang | 8f65873 | 2008-11-18 17:48:22 +0800 | [diff] [blame] | 1185 | else | 
|  | 1186 | put_user(1, p); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 1187 | } | 
| Graf Yang | 8f65873 | 2008-11-18 17:48:22 +0800 | [diff] [blame] | 1188 | spin_unlock(&bfin_spinlock_lock); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 1189 | return ret; | 
|  | 1190 | } | 
|  | 1191 |  | 
| Mike Frysinger | 1ffe664 | 2007-08-05 17:14:04 +0800 | [diff] [blame] | 1192 | int bfin_request_exception(unsigned int exception, void (*handler)(void)) | 
|  | 1193 | { | 
|  | 1194 | void (*curr_handler)(void); | 
|  | 1195 |  | 
|  | 1196 | if (exception > 0x3F) | 
|  | 1197 | return -EINVAL; | 
|  | 1198 |  | 
|  | 1199 | curr_handler = ex_table[exception]; | 
|  | 1200 |  | 
|  | 1201 | if (curr_handler != ex_replaceable) | 
|  | 1202 | return -EBUSY; | 
|  | 1203 |  | 
|  | 1204 | ex_table[exception] = handler; | 
|  | 1205 |  | 
|  | 1206 | return 0; | 
|  | 1207 | } | 
|  | 1208 | EXPORT_SYMBOL(bfin_request_exception); | 
|  | 1209 |  | 
|  | 1210 | int bfin_free_exception(unsigned int exception, void (*handler)(void)) | 
|  | 1211 | { | 
|  | 1212 | void (*curr_handler)(void); | 
|  | 1213 |  | 
|  | 1214 | if (exception > 0x3F) | 
|  | 1215 | return -EINVAL; | 
|  | 1216 |  | 
|  | 1217 | curr_handler = ex_table[exception]; | 
|  | 1218 |  | 
|  | 1219 | if (curr_handler != handler) | 
|  | 1220 | return -EBUSY; | 
|  | 1221 |  | 
|  | 1222 | ex_table[exception] = ex_replaceable; | 
|  | 1223 |  | 
|  | 1224 | return 0; | 
|  | 1225 | } | 
|  | 1226 | EXPORT_SYMBOL(bfin_free_exception); | 
|  | 1227 |  | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 1228 | void panic_cplb_error(int cplb_panic, struct pt_regs *fp) | 
|  | 1229 | { | 
|  | 1230 | switch (cplb_panic) { | 
|  | 1231 | case CPLB_NO_UNLOCKED: | 
|  | 1232 | printk(KERN_EMERG "All CPLBs are locked\n"); | 
|  | 1233 | break; | 
|  | 1234 | case CPLB_PROT_VIOL: | 
|  | 1235 | return; | 
|  | 1236 | case CPLB_NO_ADDR_MATCH: | 
|  | 1237 | return; | 
|  | 1238 | case CPLB_UNKNOWN_ERR: | 
|  | 1239 | printk(KERN_EMERG "Unknown CPLB Exception\n"); | 
|  | 1240 | break; | 
|  | 1241 | } | 
|  | 1242 |  | 
| Robin Getz | 226eb1e | 2007-10-29 17:59:07 +0800 | [diff] [blame] | 1243 | oops_in_progress = 1; | 
|  | 1244 |  | 
| Mike Frysinger | 49dce91 | 2007-11-21 16:46:49 +0800 | [diff] [blame] | 1245 | dump_bfin_process(fp); | 
| Robin Getz | b03b08b | 2007-12-23 22:57:01 +0800 | [diff] [blame] | 1246 | dump_bfin_mem(fp); | 
| Mike Frysinger | 49dce91 | 2007-11-21 16:46:49 +0800 | [diff] [blame] | 1247 | show_regs(fp); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 1248 | dump_stack(); | 
|  | 1249 | panic("Unrecoverable event\n"); | 
|  | 1250 | } |