traps.c 34.9 KB
Newer Older
B
Bryan Wu 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
/*
 * File:         arch/blackfin/kernel/traps.c
 * Based on:
 * Author:       Hamish Macdonald
 *
 * Created:
 * Description:  uses S/W interrupt 15 for the system calls
 *
 * Modified:
 *               Copyright 2004-2006 Analog Devices Inc.
 *
 * Bugs:         Enter bugs at http://blackfin.uclinux.org/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see the file COPYING, or write
 * to the Free Software Foundation, Inc.,
 * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

30 31 32 33
#include <linux/uaccess.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/kallsyms.h>
34
#include <linux/fs.h>
B
Bryan Wu 已提交
35 36
#include <asm/traps.h>
#include <asm/cacheflush.h>
37
#include <asm/cplb.h>
B
Bryan Wu 已提交
38 39
#include <asm/blackfin.h>
#include <asm/irq_handler.h>
40
#include <linux/irq.h>
41
#include <asm/trace.h>
42
#include <asm/fixed_code.h>
B
Bryan Wu 已提交
43 44 45

#ifdef CONFIG_KGDB
# include <linux/kgdb.h>
46 47 48

# define CHK_DEBUGGER_TRAP() \
	do { \
49
		kgdb_handle_exception(trapnr, sig, info.si_code, fp); \
50 51 52 53 54 55 56 57 58
	} while (0)
# define CHK_DEBUGGER_TRAP_MAYBE() \
	do { \
		if (kgdb_connected) \
			CHK_DEBUGGER_TRAP(); \
	} while (0)
#else
# define CHK_DEBUGGER_TRAP() do { } while (0)
# define CHK_DEBUGGER_TRAP_MAYBE() do { } while (0)
B
Bryan Wu 已提交
59 60
#endif

61 62 63 64 65 66 67 68 69

#ifdef CONFIG_VERBOSE_DEBUG
#define verbose_printk(fmt, arg...) \
	printk(fmt, ##arg)
#else
#define verbose_printk(fmt, arg...) \
	({ if (0) printk(fmt, ##arg); 0; })
#endif

B
Bryan Wu 已提交
70 71 72 73 74 75 76 77
/* Initiate the event table handler */
void __init trap_init(void)
{
	CSYNC();
	bfin_write_EVT3(trap);
	CSYNC();
}

78 79 80 81 82 83 84 85 86
/*
 * Used to save the RETX, SEQSTAT, I/D CPLB FAULT ADDR
 * values across the transition from exception to IRQ5.
 * We put these in L1, so they are going to be in a valid
 * location during exception context
 */
__attribute__((l1_data))
unsigned long saved_retx, saved_seqstat,
	saved_icplb_fault_addr, saved_dcplb_fault_addr;
87

88
static void decode_address(char *buf, unsigned long address)
B
Bryan Wu 已提交
89
{
90
#ifdef CONFIG_DEBUG_VERBOSE
B
Bryan Wu 已提交
91 92 93
	struct vm_list_struct *vml;
	struct task_struct *p;
	struct mm_struct *mm;
94
	unsigned long flags, offset;
95
	unsigned char in_atomic = (bfin_read_IPEND() & 0x10) || in_atomic();
B
Bryan Wu 已提交
96 97

#ifdef CONFIG_KALLSYMS
98
	unsigned long symsize;
B
Bryan Wu 已提交
99 100 101 102 103 104 105 106 107 108 109 110
	const char *symname;
	char *modname;
	char *delim = ":";
	char namebuf[128];

	/* look up the address and see if we are in kernel space */
	symname = kallsyms_lookup(address, &symsize, &offset, &modname, namebuf);

	if (symname) {
		/* yeah! kernel space! */
		if (!modname)
			modname = delim = "";
111
		sprintf(buf, "<0x%p> { %s%s%s%s + 0x%lx }",
112
		              (void *)address, delim, modname, delim, symname,
B
Bryan Wu 已提交
113
		              (unsigned long)offset);
114
		return;
B
Bryan Wu 已提交
115 116 117 118

	}
#endif

119 120 121 122 123 124 125 126 127 128 129 130
	/* Problem in fixed code section? */
	if (address >= FIXED_CODE_START && address < FIXED_CODE_END) {
		sprintf(buf, "<0x%p> /* Maybe fixed code section */", (void *)address);
		return;
	}

	/* Problem somewhere before the kernel start address */
	if (address < CONFIG_BOOT_LOAD) {
		sprintf(buf, "<0x%p> /* Maybe null pointer? */", (void *)address);
		return;
	}

B
Bryan Wu 已提交
131 132 133 134
	/* looks like we're off in user-land, so let's walk all the
	 * mappings of all our processes and see if we can't be a whee
	 * bit more specific
	 */
135
	write_lock_irqsave(&tasklist_lock, flags);
B
Bryan Wu 已提交
136
	for_each_process(p) {
137
		mm = (in_atomic ? p->mm : get_task_mm(p));
B
Bryan Wu 已提交
138 139 140 141 142 143 144 145
		if (!mm)
			continue;

		vml = mm->context.vmlist;
		while (vml) {
			struct vm_area_struct *vma = vml->vma;

			if (address >= vma->vm_start && address < vma->vm_end) {
146
				char _tmpbuf[256];
B
Bryan Wu 已提交
147 148
				char *name = p->comm;
				struct file *file = vma->vm_file;
149 150 151 152

				if (file)
					name = d_path(&file->f_path, _tmpbuf,
						      sizeof(_tmpbuf));
B
Bryan Wu 已提交
153

154 155 156
				/* FLAT does not have its text aligned to the start of
				 * the map while FDPIC ELF does ...
				 */
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177

				/* before we can check flat/fdpic, we need to
				 * make sure current is valid
				 */
				if ((unsigned long)current >= FIXED_CODE_START &&
				    !((unsigned long)current & 0x3)) {
					if (current->mm &&
					    (address > current->mm->start_code) &&
					    (address < current->mm->end_code))
						offset = address - current->mm->start_code;
					else
						offset = (address - vma->vm_start) +
							 (vma->vm_pgoff << PAGE_SHIFT);

					sprintf(buf, "<0x%p> [ %s + 0x%lx ]",
						(void *)address, name, offset);
				} else
					sprintf(buf, "<0x%p> [ %s vma:0x%lx-0x%lx]",
						(void *)address, name,
						vma->vm_start, vma->vm_end);

178
				if (!in_atomic)
179
					mmput(mm);
180

181 182 183
				if (!strlen(buf))
					sprintf(buf, "<0x%p> [ %s ] dynamic memory", (void *)address, name);

184
				goto done;
B
Bryan Wu 已提交
185 186 187 188
			}

			vml = vml->next;
		}
189
		if (!in_atomic)
190
			mmput(mm);
B
Bryan Wu 已提交
191 192 193
	}

	/* we were unable to find this address anywhere */
194
	sprintf(buf, "<0x%p> /* kernel dynamic memory */", (void *)address);
195 196 197

done:
	write_unlock_irqrestore(&tasklist_lock, flags);
198 199 200
#else
	sprintf(buf, " ");
#endif
B
Bryan Wu 已提交
201 202
}

203 204
asmlinkage void double_fault_c(struct pt_regs *fp)
{
205 206
	console_verbose();
	oops_in_progress = 1;
207
#ifdef CONFIG_DEBUG_VERBOSE
208
	printk(KERN_EMERG "\n" KERN_EMERG "Double Fault\n");
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
#ifdef CONFIG_DEBUG_DOUBLEFAULT_PRINT
	if (((long)fp->seqstat &  SEQSTAT_EXCAUSE) == VEC_UNCOV) {
		char buf[150];
		decode_address(buf, saved_retx);
		printk(KERN_EMERG "While handling exception (EXCAUSE = 0x%x) at %s:\n",
			(int)saved_seqstat & SEQSTAT_EXCAUSE, buf);
		decode_address(buf, saved_dcplb_fault_addr);
		printk(KERN_NOTICE "   DCPLB_FAULT_ADDR: %s\n", buf);
		decode_address(buf, saved_icplb_fault_addr);
		printk(KERN_NOTICE "   ICPLB_FAULT_ADDR: %s\n", buf);

		decode_address(buf, fp->retx);
		printk(KERN_NOTICE "The instruction at %s caused a double exception\n",
			buf);
	} else
#endif
	{
		dump_bfin_process(fp);
		dump_bfin_mem(fp);
		show_regs(fp);
	}
230
#endif
231 232 233 234
	panic("Double Fault - unrecoverable event\n");

}

B
Bryan Wu 已提交
235 236
asmlinkage void trap_c(struct pt_regs *fp)
{
237 238 239 240
#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
	int j;
#endif
	int sig = 0;
B
Bryan Wu 已提交
241 242 243
	siginfo_t info;
	unsigned long trapnr = fp->seqstat & SEQSTAT_EXCAUSE;

244 245 246 247 248 249 250 251 252 253
	trace_buffer_save(j);

	/* Important - be very careful dereferncing pointers - will lead to
	 * double faults if the stack has become corrupt
	 */

	/* If the fault was caused by a kernel thread, or interrupt handler
	 * we will kernel panic, so the system reboots.
	 * If KGDB is enabled, don't set this for kernel breakpoints
	*/
254 255 256 257

	/* TODO: check to see if we are in some sort of deferred HWERR
	 * that we should be able to recover from, not kernel panic
	 */
258
	if ((bfin_read_IPEND() & 0xFFC0) && (trapnr != VEC_STEP)
B
Bryan Wu 已提交
259
#ifdef CONFIG_KGDB
260
		&& (trapnr != VEC_EXCPT02)
B
Bryan Wu 已提交
261
#endif
262 263 264 265 266 267 268 269 270
	){
		console_verbose();
		oops_in_progress = 1;
	} else if (current) {
		if (current->mm == NULL) {
			console_verbose();
			oops_in_progress = 1;
		}
	}
B
Bryan Wu 已提交
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301

	/* trap_c() will be called for exceptions. During exceptions
	 * processing, the pc value should be set with retx value.
	 * With this change we can cleanup some code in signal.c- TODO
	 */
	fp->orig_pc = fp->retx;
	/* printk("exception: 0x%x, ipend=%x, reti=%x, retx=%x\n",
		trapnr, fp->ipend, fp->pc, fp->retx); */

	/* send the appropriate signal to the user program */
	switch (trapnr) {

	/* This table works in conjuction with the one in ./mach-common/entry.S
	 * Some exceptions are handled there (in assembly, in exception space)
	 * Some are handled here, (in C, in interrupt space)
	 * Some, like CPLB, are handled in both, where the normal path is
	 * handled in assembly/exception space, and the error path is handled
	 * here
	 */

	/* 0x00 - Linux Syscall, getting here is an error */
	/* 0x01 - userspace gdb breakpoint, handled here */
	case VEC_EXCPT01:
		info.si_code = TRAP_ILLTRAP;
		sig = SIGTRAP;
		CHK_DEBUGGER_TRAP_MAYBE();
		/* Check if this is a breakpoint in kernel space */
		if (fp->ipend & 0xffc0)
			return;
		else
			break;
M
Mike Frysinger 已提交
302
	/* 0x03 - User Defined, userspace stack overflow */
B
Bryan Wu 已提交
303 304 305
	case VEC_EXCPT03:
		info.si_code = SEGV_STACKFLOW;
		sig = SIGSEGV;
306
		verbose_printk(KERN_NOTICE EXC_0x03(KERN_NOTICE));
307
		CHK_DEBUGGER_TRAP_MAYBE();
B
Bryan Wu 已提交
308
		break;
309 310 311 312 313 314 315 316
	/* 0x02 - KGDB initial connection and break signal trap */
	case VEC_EXCPT02:
#ifdef CONFIG_KGDB
		info.si_code = TRAP_ILLTRAP;
		sig = SIGTRAP;
		CHK_DEBUGGER_TRAP();
		return;
#endif
317 318 319 320 321 322 323 324 325 326 327 328
	/* 0x04 - User Defined */
	/* 0x05 - User Defined */
	/* 0x06 - User Defined */
	/* 0x07 - User Defined */
	/* 0x08 - User Defined */
	/* 0x09 - User Defined */
	/* 0x0A - User Defined */
	/* 0x0B - User Defined */
	/* 0x0C - User Defined */
	/* 0x0D - User Defined */
	/* 0x0E - User Defined */
	/* 0x0F - User Defined */
329
	/* If we got here, it is most likely that someone was trying to use a
330 331 332 333 334
	 * custom exception handler, and it is not actually installed properly
	 */
	case VEC_EXCPT04 ... VEC_EXCPT15:
		info.si_code = ILL_ILLPARAOP;
		sig = SIGILL;
335
		verbose_printk(KERN_NOTICE EXC_0x04(KERN_NOTICE));
336 337
		CHK_DEBUGGER_TRAP_MAYBE();
		break;
B
Bryan Wu 已提交
338 339 340 341 342 343 344 345 346 347 348 349 350 351
	/* 0x10 HW Single step, handled here */
	case VEC_STEP:
		info.si_code = TRAP_STEP;
		sig = SIGTRAP;
		CHK_DEBUGGER_TRAP_MAYBE();
		/* Check if this is a single step in kernel space */
		if (fp->ipend & 0xffc0)
			return;
		else
			break;
	/* 0x11 - Trace Buffer Full, handled here */
	case VEC_OVFLOW:
		info.si_code = TRAP_TRACEFLOW;
		sig = SIGTRAP;
352
		verbose_printk(KERN_NOTICE EXC_0x11(KERN_NOTICE));
353
		CHK_DEBUGGER_TRAP_MAYBE();
B
Bryan Wu 已提交
354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
		break;
	/* 0x12 - Reserved, Caught by default */
	/* 0x13 - Reserved, Caught by default */
	/* 0x14 - Reserved, Caught by default */
	/* 0x15 - Reserved, Caught by default */
	/* 0x16 - Reserved, Caught by default */
	/* 0x17 - Reserved, Caught by default */
	/* 0x18 - Reserved, Caught by default */
	/* 0x19 - Reserved, Caught by default */
	/* 0x1A - Reserved, Caught by default */
	/* 0x1B - Reserved, Caught by default */
	/* 0x1C - Reserved, Caught by default */
	/* 0x1D - Reserved, Caught by default */
	/* 0x1E - Reserved, Caught by default */
	/* 0x1F - Reserved, Caught by default */
	/* 0x20 - Reserved, Caught by default */
	/* 0x21 - Undefined Instruction, handled here */
	case VEC_UNDEF_I:
		info.si_code = ILL_ILLOPC;
		sig = SIGILL;
374
		verbose_printk(KERN_NOTICE EXC_0x21(KERN_NOTICE));
375
		CHK_DEBUGGER_TRAP_MAYBE();
B
Bryan Wu 已提交
376 377 378 379 380
		break;
	/* 0x22 - Illegal Instruction Combination, handled here */
	case VEC_ILGAL_I:
		info.si_code = ILL_ILLPARAOP;
		sig = SIGILL;
381
		verbose_printk(KERN_NOTICE EXC_0x22(KERN_NOTICE));
382
		CHK_DEBUGGER_TRAP_MAYBE();
B
Bryan Wu 已提交
383
		break;
384
	/* 0x23 - Data CPLB protection violation, handled here */
B
Bryan Wu 已提交
385 386
	case VEC_CPLB_VL:
		info.si_code = ILL_CPLB_VI;
387
		sig = SIGBUS;
388
		verbose_printk(KERN_NOTICE EXC_0x23(KERN_NOTICE));
389
		CHK_DEBUGGER_TRAP_MAYBE();
B
Bryan Wu 已提交
390 391 392 393 394
		break;
	/* 0x24 - Data access misaligned, handled here */
	case VEC_MISALI_D:
		info.si_code = BUS_ADRALN;
		sig = SIGBUS;
395
		verbose_printk(KERN_NOTICE EXC_0x24(KERN_NOTICE));
396
		CHK_DEBUGGER_TRAP_MAYBE();
B
Bryan Wu 已提交
397 398 399 400 401
		break;
	/* 0x25 - Unrecoverable Event, handled here */
	case VEC_UNCOV:
		info.si_code = ILL_ILLEXCPT;
		sig = SIGILL;
402
		verbose_printk(KERN_NOTICE EXC_0x25(KERN_NOTICE));
403
		CHK_DEBUGGER_TRAP_MAYBE();
B
Bryan Wu 已提交
404 405 406 407 408 409
		break;
	/* 0x26 - Data CPLB Miss, normal case is handled in _cplb_hdr,
		error case is handled here */
	case VEC_CPLB_M:
		info.si_code = BUS_ADRALN;
		sig = SIGBUS;
410
		verbose_printk(KERN_NOTICE EXC_0x26(KERN_NOTICE));
B
Bryan Wu 已提交
411 412 413 414 415
		break;
	/* 0x27 - Data CPLB Multiple Hits - Linux Trap Zero, handled here */
	case VEC_CPLB_MHIT:
		info.si_code = ILL_CPLB_MULHIT;
		sig = SIGSEGV;
416
#ifdef CONFIG_DEBUG_HUNT_FOR_ZERO
417
		if (saved_dcplb_fault_addr < FIXED_CODE_START)
418
			verbose_printk(KERN_NOTICE "NULL pointer access\n");
419
		else
B
Bryan Wu 已提交
420
#endif
421
			verbose_printk(KERN_NOTICE EXC_0x27(KERN_NOTICE));
422
		CHK_DEBUGGER_TRAP_MAYBE();
B
Bryan Wu 已提交
423 424 425 426 427
		break;
	/* 0x28 - Emulation Watchpoint, handled here */
	case VEC_WATCH:
		info.si_code = TRAP_WATCHPT;
		sig = SIGTRAP;
428
		pr_debug(EXC_0x28(KERN_DEBUG));
B
Bryan Wu 已提交
429 430 431 432 433 434 435 436 437 438 439
		CHK_DEBUGGER_TRAP_MAYBE();
		/* Check if this is a watchpoint in kernel space */
		if (fp->ipend & 0xffc0)
			return;
		else
			break;
#ifdef CONFIG_BF535
	/* 0x29 - Instruction fetch access error (535 only) */
	case VEC_ISTRU_VL:      /* ADSP-BF535 only (MH) */
		info.si_code = BUS_OPFETCH;
		sig = SIGBUS;
440
		verbose_printk(KERN_NOTICE "BF535: VEC_ISTRU_VL\n");
441
		CHK_DEBUGGER_TRAP_MAYBE();
B
Bryan Wu 已提交
442 443 444 445 446 447 448 449
		break;
#else
	/* 0x29 - Reserved, Caught by default */
#endif
	/* 0x2A - Instruction fetch misaligned, handled here */
	case VEC_MISALI_I:
		info.si_code = BUS_ADRALN;
		sig = SIGBUS;
450
		verbose_printk(KERN_NOTICE EXC_0x2A(KERN_NOTICE));
451
		CHK_DEBUGGER_TRAP_MAYBE();
B
Bryan Wu 已提交
452
		break;
453
	/* 0x2B - Instruction CPLB protection violation, handled here */
B
Bryan Wu 已提交
454 455
	case VEC_CPLB_I_VL:
		info.si_code = ILL_CPLB_VI;
456
		sig = SIGBUS;
457
		verbose_printk(KERN_NOTICE EXC_0x2B(KERN_NOTICE));
458
		CHK_DEBUGGER_TRAP_MAYBE();
B
Bryan Wu 已提交
459 460 461 462 463
		break;
	/* 0x2C - Instruction CPLB miss, handled in _cplb_hdr */
	case VEC_CPLB_I_M:
		info.si_code = ILL_CPLB_MISS;
		sig = SIGBUS;
464
		verbose_printk(KERN_NOTICE EXC_0x2C(KERN_NOTICE));
B
Bryan Wu 已提交
465 466 467 468 469
		break;
	/* 0x2D - Instruction CPLB Multiple Hits, handled here */
	case VEC_CPLB_I_MHIT:
		info.si_code = ILL_CPLB_MULHIT;
		sig = SIGSEGV;
470
#ifdef CONFIG_DEBUG_HUNT_FOR_ZERO
471
		if (saved_icplb_fault_addr < FIXED_CODE_START)
472
			verbose_printk(KERN_NOTICE "Jump to NULL address\n");
473
		else
B
Bryan Wu 已提交
474
#endif
475
			verbose_printk(KERN_NOTICE EXC_0x2D(KERN_NOTICE));
476
		CHK_DEBUGGER_TRAP_MAYBE();
B
Bryan Wu 已提交
477 478 479 480 481
		break;
	/* 0x2E - Illegal use of Supervisor Resource, handled here */
	case VEC_ILL_RES:
		info.si_code = ILL_PRVOPC;
		sig = SIGILL;
482
		verbose_printk(KERN_NOTICE EXC_0x2E(KERN_NOTICE));
483
		CHK_DEBUGGER_TRAP_MAYBE();
B
Bryan Wu 已提交
484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501
		break;
	/* 0x2F - Reserved, Caught by default */
	/* 0x30 - Reserved, Caught by default */
	/* 0x31 - Reserved, Caught by default */
	/* 0x32 - Reserved, Caught by default */
	/* 0x33 - Reserved, Caught by default */
	/* 0x34 - Reserved, Caught by default */
	/* 0x35 - Reserved, Caught by default */
	/* 0x36 - Reserved, Caught by default */
	/* 0x37 - Reserved, Caught by default */
	/* 0x38 - Reserved, Caught by default */
	/* 0x39 - Reserved, Caught by default */
	/* 0x3A - Reserved, Caught by default */
	/* 0x3B - Reserved, Caught by default */
	/* 0x3C - Reserved, Caught by default */
	/* 0x3D - Reserved, Caught by default */
	/* 0x3E - Reserved, Caught by default */
	/* 0x3F - Reserved, Caught by default */
502 503 504 505 506 507 508 509
	case VEC_HWERR:
		info.si_code = BUS_ADRALN;
		sig = SIGBUS;
		switch (fp->seqstat & SEQSTAT_HWERRCAUSE) {
		/* System MMR Error */
		case (SEQSTAT_HWERRCAUSE_SYSTEM_MMR):
			info.si_code = BUS_ADRALN;
			sig = SIGBUS;
510
			verbose_printk(KERN_NOTICE HWC_x2(KERN_NOTICE));
511 512 513 514 515
			break;
		/* External Memory Addressing Error */
		case (SEQSTAT_HWERRCAUSE_EXTERN_ADDR):
			info.si_code = BUS_ADRERR;
			sig = SIGBUS;
516
			verbose_printk(KERN_NOTICE HWC_x3(KERN_NOTICE));
517 518 519
			break;
		/* Performance Monitor Overflow */
		case (SEQSTAT_HWERRCAUSE_PERF_FLOW):
520
			verbose_printk(KERN_NOTICE HWC_x12(KERN_NOTICE));
521 522 523 524 525 526 527 528 529
			break;
		/* RAISE 5 instruction */
		case (SEQSTAT_HWERRCAUSE_RAISE_5):
			printk(KERN_NOTICE HWC_x18(KERN_NOTICE));
			break;
		default:        /* Reserved */
			printk(KERN_NOTICE HWC_default(KERN_NOTICE));
			break;
		}
530
		CHK_DEBUGGER_TRAP_MAYBE();
531
		break;
532 533 534 535
	/*
	 * We should be handling all known exception types above,
	 * if we get here we hit a reserved one, so panic
	 */
B
Bryan Wu 已提交
536
	default:
537 538 539
		oops_in_progress = 1;
		info.si_code = ILL_ILLPARAOP;
		sig = SIGILL;
540
		verbose_printk(KERN_EMERG "Caught Unhandled Exception, code = %08lx\n",
B
Bryan Wu 已提交
541
			(fp->seqstat & SEQSTAT_EXCAUSE));
542
		CHK_DEBUGGER_TRAP_MAYBE();
B
Bryan Wu 已提交
543 544 545
		break;
	}

546 547 548
	BUG_ON(sig == 0);

	if (sig != SIGTRAP) {
549
		dump_bfin_process(fp);
550
		dump_bfin_mem(fp);
551
		show_regs(fp);
552 553 554 555

		/* Print out the trace buffer if it makes sense */
#ifndef CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE
		if (trapnr == VEC_CPLB_I_M || trapnr == VEC_CPLB_M)
556
			verbose_printk(KERN_NOTICE "No trace since you do not have "
557 558 559 560 561
				"CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE enabled\n"
				KERN_NOTICE "\n");
		else
#endif
			dump_bfin_trace_buffer();
562

563
		if (oops_in_progress) {
564
			/* Dump the current kernel stack */
565
			verbose_printk(KERN_NOTICE "\n" KERN_NOTICE "Kernel Stack\n");
566
			show_stack(current, NULL);
567
			print_modules();
568
#ifndef CONFIG_ACCESS_CHECK
569
			verbose_printk(KERN_EMERG "Please turn on "
570
			       "CONFIG_ACCESS_CHECK\n");
571
#endif
B
Bryan Wu 已提交
572
			panic("Kernel exception");
573
		} else {
574 575
#ifdef CONFIG_VERBOSE_DEBUG
			unsigned long *stack;
576 577
			/* Dump the user space stack */
			stack = (unsigned long *)rdusp();
578
			verbose_printk(KERN_NOTICE "Userspace Stack\n");
579
			show_stack(NULL, stack);
580
#endif
581
		}
B
Bryan Wu 已提交
582
	}
583

584 585
	info.si_signo = sig;
	info.si_errno = 0;
586
	info.si_addr = (void __user *)fp->pc;
587
	force_sig_info(sig, &info, current);
B
Bryan Wu 已提交
588 589 590 591 592 593 594

	trace_buffer_restore(j);
	return;
}

/* Typical exception handling routines	*/

595 596
#define EXPAND_LEN ((1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN) * 256 - 1)

597 598 599 600
/*
 * Similar to get_user, do some address checking, then dereference
 * Return true on sucess, false on bad address
 */
601
static bool get_instruction(unsigned short *val, unsigned short *address)
602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621
{

	unsigned long addr;

	addr = (unsigned long)address;

	/* Check for odd addresses */
	if (addr & 0x1)
		return false;

	/* Check that things do not wrap around */
	if (addr > (addr + 2))
		return false;

	/*
	 * Since we are in exception context, we need to do a little address checking
	 * We need to make sure we are only accessing valid memory, and
	 * we don't read something in the async space that can hang forever
	 */
	if ((addr >= FIXED_CODE_START && (addr + 2) <= physical_mem_end) ||
622
#if L2_LENGTH != 0
623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646
	    (addr >= L2_START && (addr + 2) <= (L2_START + L2_LENGTH)) ||
#endif
	    (addr >= BOOT_ROM_START && (addr + 2) <= (BOOT_ROM_START + BOOT_ROM_LENGTH)) ||
#if L1_DATA_A_LENGTH != 0
	    (addr >= L1_DATA_A_START && (addr + 2) <= (L1_DATA_A_START + L1_DATA_A_LENGTH)) ||
#endif
#if L1_DATA_B_LENGTH != 0
	    (addr >= L1_DATA_B_START && (addr + 2) <= (L1_DATA_B_START + L1_DATA_B_LENGTH)) ||
#endif
	    (addr >= L1_SCRATCH_START && (addr + 2) <= (L1_SCRATCH_START + L1_SCRATCH_LENGTH)) ||
	    (!(bfin_read_EBIU_AMBCTL0() & B0RDYEN) &&
	       addr >= ASYNC_BANK0_BASE && (addr + 2) <= (ASYNC_BANK0_BASE + ASYNC_BANK0_SIZE)) ||
	    (!(bfin_read_EBIU_AMBCTL0() & B1RDYEN) &&
	       addr >= ASYNC_BANK1_BASE && (addr + 2) <= (ASYNC_BANK1_BASE + ASYNC_BANK1_SIZE)) ||
	    (!(bfin_read_EBIU_AMBCTL1() & B2RDYEN) &&
	       addr >= ASYNC_BANK2_BASE && (addr + 2) <= (ASYNC_BANK2_BASE + ASYNC_BANK1_SIZE)) ||
	    (!(bfin_read_EBIU_AMBCTL1() & B3RDYEN) &&
	      addr >= ASYNC_BANK3_BASE && (addr + 2) <= (ASYNC_BANK3_BASE + ASYNC_BANK1_SIZE))) {
		*val = *address;
		return true;
	}

#if L1_CODE_LENGTH != 0
	if (addr >= L1_CODE_START && (addr + 2) <= (L1_CODE_START + L1_CODE_LENGTH)) {
647
		isram_memcpy(val, address, 2);
648 649 650 651 652 653 654 655
		return true;
	}
#endif


	return false;
}

656 657 658 659 660 661
/* 
 * decode the instruction if we are printing out the trace, as it
 * makes things easier to follow, without running it through objdump
 * These are the normal instructions which cause change of flow, which
 * would be at the source of the trace buffer
 */
662 663
#ifdef CONFIG_DEBUG_VERBOSE
static void decode_instruction(unsigned short *address)
664 665 666 667 668
{
	unsigned short opcode;

	if (get_instruction(&opcode, address)) {
		if (opcode == 0x0010)
669
			verbose_printk("RTS");
670
		else if (opcode == 0x0011)
671
			verbose_printk("RTI");
672
		else if (opcode == 0x0012)
673
			verbose_printk("RTX");
674
		else if (opcode >= 0x0050 && opcode <= 0x0057)
675
			verbose_printk("JUMP (P%i)", opcode & 7);
676
		else if (opcode >= 0x0060 && opcode <= 0x0067)
677
			verbose_printk("CALL (P%i)", opcode & 7);
678
		else if (opcode >= 0x0070 && opcode <= 0x0077)
679
			verbose_printk("CALL (PC+P%i)", opcode & 7);
680
		else if (opcode >= 0x0080 && opcode <= 0x0087)
681
			verbose_printk("JUMP (PC+P%i)", opcode & 7);
682
		else if ((opcode >= 0x1000 && opcode <= 0x13FF) || (opcode >= 0x1800 && opcode <= 0x1BFF))
683
			verbose_printk("IF !CC JUMP");
684
		else if ((opcode >= 0x1400 && opcode <= 0x17ff) || (opcode >= 0x1c00 && opcode <= 0x1fff))
685
			verbose_printk("IF CC JUMP");
686
		else if (opcode >= 0x2000 && opcode <= 0x2fff)
687
			verbose_printk("JUMP.S");
688
		else if (opcode >= 0xe080 && opcode <= 0xe0ff)
689
			verbose_printk("LSETUP");
690
		else if (opcode >= 0xe200 && opcode <= 0xe2ff)
691
			verbose_printk("JUMP.L");
692
		else if (opcode >= 0xe300 && opcode <= 0xe3ff)
693
			verbose_printk("CALL pcrel");
694
		else
695
			verbose_printk("0x%04x", opcode);
696 697 698
	}

}
699
#endif
700

B
Bryan Wu 已提交
701 702
void dump_bfin_trace_buffer(void)
{
703
#ifdef CONFIG_DEBUG_VERBOSE
704 705
#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
	int tflags, i = 0;
706
	char buf[150];
707
	unsigned short *addr;
708 709 710 711
#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND
	int j, index;
#endif

B
Bryan Wu 已提交
712 713
	trace_buffer_save(tflags);

714
	printk(KERN_NOTICE "Hardware Trace:\n");
715

716 717 718 719
#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND
	printk(KERN_NOTICE "WARNING: Expanded trace turned on - can not trace exceptions\n");
#endif

B
Bryan Wu 已提交
720
	if (likely(bfin_read_TBUFSTAT() & TBUFCNT)) {
721
		for (; bfin_read_TBUFSTAT() & TBUFCNT; i++) {
722 723
			decode_address(buf, (unsigned long)bfin_read_TBUF());
			printk(KERN_NOTICE "%4i Target : %s\n", i, buf);
724 725 726
			addr = (unsigned short *)bfin_read_TBUF();
			decode_address(buf, (unsigned long)addr);
			printk(KERN_NOTICE "     Source : %s ", buf);
727
			decode_instruction(addr);
728
			printk("\n");
B
Bryan Wu 已提交
729 730 731
		}
	}

732 733
#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND
	if (trace_buff_offset)
734
		index = trace_buff_offset / 4;
735 736 737 738 739
	else
		index = EXPAND_LEN;

	j = (1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN) * 128;
	while (j) {
740 741
		decode_address(buf, software_trace_buff[index]);
		printk(KERN_NOTICE "%4i Target : %s\n", i, buf);
742 743 744
		index -= 1;
		if (index < 0 )
			index = EXPAND_LEN;
745
		decode_address(buf, software_trace_buff[index]);
746 747 748
		printk(KERN_NOTICE "     Source : %s ", buf);
		decode_instruction((unsigned short *)software_trace_buff[index]);
		printk("\n");
749 750 751 752 753 754 755 756
		index -= 1;
		if (index < 0)
			index = EXPAND_LEN;
		j--;
		i++;
	}
#endif

B
Bryan Wu 已提交
757
	trace_buffer_restore(tflags);
758
#endif
759
#endif
B
Bryan Wu 已提交
760 761 762
}
EXPORT_SYMBOL(dump_bfin_trace_buffer);

763 764 765 766
/*
 * Checks to see if the address pointed to is either a
 * 16-bit CALL instruction, or a 32-bit CALL instruction
 */
767
static bool is_bfin_call(unsigned short *addr)
B
Bryan Wu 已提交
768
{
769 770
	unsigned short opcode = 0, *ins_addr;
	ins_addr = (unsigned short *)addr;
B
Bryan Wu 已提交
771

772 773
	if (!get_instruction(&opcode, ins_addr))
		return false;
B
Bryan Wu 已提交
774

775 776 777 778 779 780 781
	if ((opcode >= 0x0060 && opcode <= 0x0067) ||
	    (opcode >= 0x0070 && opcode <= 0x0077))
		return true;

	ins_addr--;
	if (!get_instruction(&opcode, ins_addr))
		return false;
B
Bryan Wu 已提交
782

783 784 785 786 787 788
	if (opcode >= 0xE300 && opcode <= 0xE3FF)
		return true;

	return false;

}
789

B
Bryan Wu 已提交
790 791
void show_stack(struct task_struct *task, unsigned long *stack)
{
792
#ifdef CONFIG_PRINTK
793 794 795 796
	unsigned int *addr, *endstack, *fp = 0, *frame;
	unsigned short *ins_addr;
	char buf[150];
	unsigned int i, j, ret_addr, frame_no = 0;
B
Bryan Wu 已提交
797

798 799 800 801
	/*
	 * If we have been passed a specific stack, use that one otherwise
	 *    if we have been passed a task structure, use that, otherwise
	 *    use the stack of where the variable "stack" exists
B
Bryan Wu 已提交
802 803
	 */

804 805 806
	if (stack == NULL) {
		if (task) {
			/* We know this is a kernel stack, so this is the start/end */
B
Bryan Wu 已提交
807
			stack = (unsigned long *)task->thread.ksp;
808 809 810
			endstack = (unsigned int *)(((unsigned int)(stack) & ~(THREAD_SIZE - 1)) + THREAD_SIZE);
		} else {
			/* print out the existing stack info */
B
Bryan Wu 已提交
811
			stack = (unsigned long *)&stack;
812 813 814 815 816
			endstack = (unsigned int *)PAGE_ALIGN((unsigned int)stack);
		}
	} else
		endstack = (unsigned int *)PAGE_ALIGN((unsigned int)stack);

817
	printk(KERN_NOTICE "Stack info:\n");
818
	decode_address(buf, (unsigned int)stack);
819 820
	printk(KERN_NOTICE " SP: [0x%p] %s\n", stack, buf);

821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842
	addr = (unsigned int *)((unsigned int)stack & ~0x3F);

	/* First thing is to look for a frame pointer */
	for (addr = (unsigned int *)((unsigned int)stack & ~0xF), i = 0;
		addr < endstack; addr++, i++) {
		if (*addr & 0x1)
			continue;
		ins_addr = (unsigned short *)*addr;
		ins_addr--;
		if (is_bfin_call(ins_addr))
			fp = addr - 1;

		if (fp) {
			/* Let's check to see if it is a frame pointer */
			while (fp >= (addr - 1) && fp < endstack && fp)
				fp = (unsigned int *)*fp;
			if (fp == 0 || fp == endstack) {
				fp = addr - 1;
				break;
			}
			fp = 0;
		}
B
Bryan Wu 已提交
843
	}
844 845 846 847 848
	if (fp) {
		frame = fp;
		printk(" FP: (0x%p)\n", fp);
	} else
		frame = 0;
B
Bryan Wu 已提交
849

850 851 852 853 854 855
	/*
	 * Now that we think we know where things are, we
	 * walk the stack again, this time printing things out
	 * incase there is no frame pointer, we still look for
	 * valid return addresses
	 */
B
Bryan Wu 已提交
856

857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909
	/* First time print out data, next time, print out symbols */
	for (j = 0; j <= 1; j++) {
		if (j)
			printk(KERN_NOTICE "Return addresses in stack:\n");
		else
			printk(KERN_NOTICE " Memory from 0x%08lx to %p", ((long unsigned int)stack & ~0xF), endstack);

		fp = frame;
		frame_no = 0;

		for (addr = (unsigned int *)((unsigned int)stack & ~0xF), i = 0;
		     addr <= endstack; addr++, i++) {

			ret_addr = 0;
			if (!j && i % 8 == 0)
				printk("\n" KERN_NOTICE "%p:",addr);

			/* if it is an odd address, or zero, just skip it */
			if (*addr & 0x1 || !*addr)
				goto print;

			ins_addr = (unsigned short *)*addr;

			/* Go back one instruction, and see if it is a CALL */
			ins_addr--;
			ret_addr = is_bfin_call(ins_addr);
 print:
			if (!j && stack == (unsigned long *)addr)
				printk("[%08x]", *addr);
			else if (ret_addr)
				if (j) {
					decode_address(buf, (unsigned int)*addr);
					if (frame == addr) {
						printk(KERN_NOTICE "   frame %2i : %s\n", frame_no, buf);
						continue;
					}
					printk(KERN_NOTICE "    address : %s\n", buf);
				} else
					printk("<%08x>", *addr);
			else if (fp == addr) {
				if (j)
					frame = addr+1;
				else
					printk("(%08x)", *addr);

				fp = (unsigned int *)*addr;
				frame_no++;

			} else if (!j)
				printk(" %08x ", *addr);
		}
		if (!j)
			printk("\n");
B
Bryan Wu 已提交
910
	}
911
#endif
B
Bryan Wu 已提交
912 913 914 915 916
}

void dump_stack(void)
{
	unsigned long stack;
917
#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
B
Bryan Wu 已提交
918
	int tflags;
919
#endif
B
Bryan Wu 已提交
920 921 922 923 924 925 926
	trace_buffer_save(tflags);
	dump_bfin_trace_buffer();
	show_stack(current, &stack);
	trace_buffer_restore(tflags);
}
EXPORT_SYMBOL(dump_stack);

927
void dump_bfin_process(struct pt_regs *fp)
B
Bryan Wu 已提交
928
{
929
#ifdef CONFIG_DEBUG_VERBOSE
930 931 932 933 934
	/* We should be able to look at fp->ipend, but we don't push it on the
	 * stack all the time, so do this until we fix that */
	unsigned int context = bfin_read_IPEND();

	if (oops_in_progress)
935
		verbose_printk(KERN_EMERG "Kernel OOPS in progress\n");
936

937
	if (context & 0x0020 && (fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR)
938
		verbose_printk(KERN_NOTICE "HW Error context\n");
939
	else if (context & 0x0020)
940
		verbose_printk(KERN_NOTICE "Deferred Exception context\n");
941
	else if (context & 0x3FC0)
942
		verbose_printk(KERN_NOTICE "Interrupt context\n");
943
	else if (context & 0x4000)
944
		verbose_printk(KERN_NOTICE "Deferred Interrupt context\n");
945
	else if (context & 0x8000)
946
		verbose_printk(KERN_NOTICE "Kernel process context\n");
947

948 949 950
	/* Because we are crashing, and pointers could be bad, we check things
	 * pretty closely before we use them
	 */
951 952
	if ((unsigned long)current >= FIXED_CODE_START &&
	    !((unsigned long)current & 0x3) && current->pid) {
953
		verbose_printk(KERN_NOTICE "CURRENT PROCESS:\n");
954
		if (current->comm >= (char *)FIXED_CODE_START)
955
			verbose_printk(KERN_NOTICE "COMM=%s PID=%d\n",
956 957
				current->comm, current->pid);
		else
958
			verbose_printk(KERN_NOTICE "COMM= invalid\n");
959 960

		if (!((unsigned long)current->mm & 0x3) && (unsigned long)current->mm >= FIXED_CODE_START)
961
			verbose_printk(KERN_NOTICE  "TEXT = 0x%p-0x%p        DATA = 0x%p-0x%p\n"
962 963 964 965 966 967 968 969 970 971
				KERN_NOTICE " BSS = 0x%p-0x%p  USER-STACK = 0x%p\n"
				KERN_NOTICE "\n",
				(void *)current->mm->start_code,
				(void *)current->mm->end_code,
				(void *)current->mm->start_data,
				(void *)current->mm->end_data,
				(void *)current->mm->end_data,
				(void *)current->mm->brk,
				(void *)current->mm->start_stack);
		else
972
			verbose_printk(KERN_NOTICE "invalid mm\n");
973
	} else
974
		verbose_printk(KERN_NOTICE "\n" KERN_NOTICE
975
		     "No Valid process in current context\n");
976
#endif
977
}
978

979
void dump_bfin_mem(struct pt_regs *fp)
980
{
981
#ifdef CONFIG_DEBUG_VERBOSE
982 983
	unsigned short *addr, *erraddr, val = 0, err = 0;
	char sti = 0, buf[6];
B
Bryan Wu 已提交
984

985
	erraddr = (void *)fp->pc;
986

987
	verbose_printk(KERN_NOTICE "return address: [0x%p]; contents of:", erraddr);
988 989 990 991 992

	for (addr = (unsigned short *)((unsigned long)erraddr & ~0xF) - 0x10;
	     addr < (unsigned short *)((unsigned long)erraddr & ~0xF) + 0x10;
	     addr++) {
		if (!((unsigned long)addr & 0xF))
993
			verbose_printk("\n" KERN_NOTICE "0x%p: ", addr);
994

995
		if (!get_instruction(&val, addr)) {
996 997 998 999 1000 1001
				val = 0;
				sprintf(buf, "????");
		} else
			sprintf(buf, "%04x", val);

		if (addr == erraddr) {
1002
			verbose_printk("[%s]", buf);
1003 1004
			err = val;
		} else
1005
			verbose_printk(" %s ", buf);
1006 1007 1008 1009 1010 1011 1012 1013

		/* Do any previous instructions turn on interrupts? */
		if (addr <= erraddr &&				/* in the past */
		    ((val >= 0x0040 && val <= 0x0047) ||	/* STI instruction */
		      val == 0x017b))				/* [SP++] = RETI */
			sti = 1;
	}

1014
	verbose_printk("\n");
1015 1016 1017 1018

	/* Hardware error interrupts can be deferred */
	if (unlikely(sti && (fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR &&
	    oops_in_progress)){
1019
		verbose_printk(KERN_NOTICE "Looks like this was a deferred error - sorry\n");
B
Bryan Wu 已提交
1020
#ifndef CONFIG_DEBUG_HWERR
1021
		verbose_printk(KERN_NOTICE "The remaining message may be meaningless\n"
1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034
			KERN_NOTICE "You should enable CONFIG_DEBUG_HWERR to get a"
			 " better idea where it came from\n");
#else
		/* If we are handling only one peripheral interrupt
		 * and current mm and pid are valid, and the last error
		 * was in that user space process's text area
		 * print it out - because that is where the problem exists
		 */
		if ((!(((fp)->ipend & ~0x30) & (((fp)->ipend & ~0x30) - 1))) &&
		     (current->pid && current->mm)) {
			/* And the last RETI points to the current userspace context */
			if ((fp + 1)->pc >= current->mm->start_code &&
			    (fp + 1)->pc <= current->mm->end_code) {
1035 1036
				verbose_printk(KERN_NOTICE "It might be better to look around here : \n");
				verbose_printk(KERN_NOTICE "-------------------------------------------\n");
1037
				show_regs(fp + 1);
1038
				verbose_printk(KERN_NOTICE "-------------------------------------------\n");
1039
			}
B
Bryan Wu 已提交
1040
		}
1041 1042
#endif
	}
1043
#endif
1044 1045 1046 1047
}

void show_regs(struct pt_regs *fp)
{
1048
#ifdef CONFIG_DEBUG_VERBOSE
1049
	char buf [150];
1050 1051 1052
	struct irqaction *action;
	unsigned int i;
	unsigned long flags;
1053

1054 1055
	verbose_printk(KERN_NOTICE "\n" KERN_NOTICE "SEQUENCER STATUS:\t\t%s\n", print_tainted());
	verbose_printk(KERN_NOTICE " SEQSTAT: %08lx  IPEND: %04lx  SYSCFG: %04lx\n",
1056
		(long)fp->seqstat, fp->ipend, fp->syscfg);
1057
	if ((fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR) {
1058
		verbose_printk(KERN_NOTICE "  HWERRCAUSE: 0x%lx\n",
1059 1060 1061 1062
			(fp->seqstat & SEQSTAT_HWERRCAUSE) >> 14);
#ifdef EBIU_ERRMST
		/* If the error was from the EBIU, print it out */
		if (bfin_read_EBIU_ERRMST() & CORE_ERROR) {
1063
			verbose_printk(KERN_NOTICE "  EBIU Error Reason  : 0x%04x\n",
1064
				bfin_read_EBIU_ERRMST());
1065
			verbose_printk(KERN_NOTICE "  EBIU Error Address : 0x%08x\n",
1066 1067 1068 1069
				bfin_read_EBIU_ERRADD());
		}
#endif
	}
1070
	verbose_printk(KERN_NOTICE "  EXCAUSE   : 0x%lx\n",
1071
		fp->seqstat & SEQSTAT_EXCAUSE);
1072 1073 1074
	for (i = 6; i <= 15 ; i++) {
		if (fp->ipend & (1 << i)) {
			decode_address(buf, bfin_read32(EVT0 + 4*i));
1075
			verbose_printk(KERN_NOTICE "  physical IVG%i asserted : %s\n", i, buf);
1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087
		}
	}

	/* if no interrupts are going off, don't print this out */
	if (fp->ipend & ~0x3F) {
		for (i = 0; i < (NR_IRQS - 1); i++) {
			spin_lock_irqsave(&irq_desc[i].lock, flags);
			action = irq_desc[i].action;
			if (!action)
				goto unlock;

			decode_address(buf, (unsigned int)action->handler);
1088
			verbose_printk(KERN_NOTICE "  logical irq %3d mapped  : %s", i, buf);
1089 1090
			for (action = action->next; action; action = action->next) {
				decode_address(buf, (unsigned int)action->handler);
1091
				verbose_printk(", %s", buf);
1092
			}
1093
			verbose_printk("\n");
1094 1095 1096 1097
unlock:
			spin_unlock_irqrestore(&irq_desc[i].lock, flags);
		}
	}
1098

1099
	decode_address(buf, fp->rete);
1100
	verbose_printk(KERN_NOTICE " RETE: %s\n", buf);
1101
	decode_address(buf, fp->retn);
1102
	verbose_printk(KERN_NOTICE " RETN: %s\n", buf);
1103
	decode_address(buf, fp->retx);
1104
	verbose_printk(KERN_NOTICE " RETX: %s\n", buf);
1105
	decode_address(buf, fp->rets);
1106
	verbose_printk(KERN_NOTICE " RETS: %s\n", buf);
1107
	decode_address(buf, fp->pc);
1108
	verbose_printk(KERN_NOTICE " PC  : %s\n", buf);
1109

1110 1111
	if (((long)fp->seqstat &  SEQSTAT_EXCAUSE) &&
	    (((long)fp->seqstat & SEQSTAT_EXCAUSE) != VEC_HWERR)) {
1112
		decode_address(buf, saved_dcplb_fault_addr);
1113
		verbose_printk(KERN_NOTICE "DCPLB_FAULT_ADDR: %s\n", buf);
1114
		decode_address(buf, saved_icplb_fault_addr);
1115
		verbose_printk(KERN_NOTICE "ICPLB_FAULT_ADDR: %s\n", buf);
1116 1117
	}

1118 1119
	verbose_printk(KERN_NOTICE "\n" KERN_NOTICE "PROCESSOR STATE:\n");
	verbose_printk(KERN_NOTICE " R0 : %08lx    R1 : %08lx    R2 : %08lx    R3 : %08lx\n",
1120
		fp->r0, fp->r1, fp->r2, fp->r3);
1121
	verbose_printk(KERN_NOTICE " R4 : %08lx    R5 : %08lx    R6 : %08lx    R7 : %08lx\n",
1122
		fp->r4, fp->r5, fp->r6, fp->r7);
1123
	verbose_printk(KERN_NOTICE " P0 : %08lx    P1 : %08lx    P2 : %08lx    P3 : %08lx\n",
1124
		fp->p0, fp->p1, fp->p2, fp->p3);
1125
	verbose_printk(KERN_NOTICE " P4 : %08lx    P5 : %08lx    FP : %08lx    SP : %08lx\n",
1126
		fp->p4, fp->p5, fp->fp, (long)fp);
1127
	verbose_printk(KERN_NOTICE " LB0: %08lx    LT0: %08lx    LC0: %08lx\n",
1128
		fp->lb0, fp->lt0, fp->lc0);
1129
	verbose_printk(KERN_NOTICE " LB1: %08lx    LT1: %08lx    LC1: %08lx\n",
1130
		fp->lb1, fp->lt1, fp->lc1);
1131
	verbose_printk(KERN_NOTICE " B0 : %08lx    L0 : %08lx    M0 : %08lx    I0 : %08lx\n",
1132
		fp->b0, fp->l0, fp->m0, fp->i0);
1133
	verbose_printk(KERN_NOTICE " B1 : %08lx    L1 : %08lx    M1 : %08lx    I1 : %08lx\n",
1134
		fp->b1, fp->l1, fp->m1, fp->i1);
1135
	verbose_printk(KERN_NOTICE " B2 : %08lx    L2 : %08lx    M2 : %08lx    I2 : %08lx\n",
1136
		fp->b2, fp->l2, fp->m2, fp->i2);
1137
	verbose_printk(KERN_NOTICE " B3 : %08lx    L3 : %08lx    M3 : %08lx    I3 : %08lx\n",
1138
		fp->b3, fp->l3, fp->m3, fp->i3);
1139
	verbose_printk(KERN_NOTICE "A0.w: %08lx   A0.x: %08lx   A1.w: %08lx   A1.x: %08lx\n",
1140
		fp->a0w, fp->a0x, fp->a1w, fp->a1x);
1141

1142
	verbose_printk(KERN_NOTICE "USP : %08lx  ASTAT: %08lx\n",
1143
		rdusp(), fp->astat);
B
Bryan Wu 已提交
1144

1145 1146
	verbose_printk(KERN_NOTICE "\n");
#endif
B
Bryan Wu 已提交
1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169
}

#ifdef CONFIG_SYS_BFIN_SPINLOCK_L1
asmlinkage int sys_bfin_spinlock(int *spinlock)__attribute__((l1_text));
#endif

asmlinkage int sys_bfin_spinlock(int *spinlock)
{
	int ret = 0;
	int tmp = 0;

	local_irq_disable();
	ret = get_user(tmp, spinlock);
	if (ret == 0) {
		if (tmp)
			ret = 1;
		tmp = 1;
		put_user(tmp, spinlock);
	}
	local_irq_enable();
	return ret;
}

1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205
int bfin_request_exception(unsigned int exception, void (*handler)(void))
{
	void (*curr_handler)(void);

	if (exception > 0x3F)
		return -EINVAL;

	curr_handler = ex_table[exception];

	if (curr_handler != ex_replaceable)
		return -EBUSY;

	ex_table[exception] = handler;

	return 0;
}
EXPORT_SYMBOL(bfin_request_exception);

int bfin_free_exception(unsigned int exception, void (*handler)(void))
{
	void (*curr_handler)(void);

	if (exception > 0x3F)
		return -EINVAL;

	curr_handler = ex_table[exception];

	if (curr_handler != handler)
		return -EBUSY;

	ex_table[exception] = ex_replaceable;

	return 0;
}
EXPORT_SYMBOL(bfin_free_exception);

B
Bryan Wu 已提交
1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220
void panic_cplb_error(int cplb_panic, struct pt_regs *fp)
{
	switch (cplb_panic) {
	case CPLB_NO_UNLOCKED:
		printk(KERN_EMERG "All CPLBs are locked\n");
		break;
	case CPLB_PROT_VIOL:
		return;
	case CPLB_NO_ADDR_MATCH:
		return;
	case CPLB_UNKNOWN_ERR:
		printk(KERN_EMERG "Unknown CPLB Exception\n");
		break;
	}

1221 1222
	oops_in_progress = 1;

1223
	dump_bfin_process(fp);
1224
	dump_bfin_mem(fp);
1225
	show_regs(fp);
B
Bryan Wu 已提交
1226 1227 1228
	dump_stack();
	panic("Unrecoverable event\n");
}