1/* traps.c: high-level exception handler for FR-V 2 * 3 * Copyright (C) 2003 Red Hat, Inc. All Rights Reserved. 4 * Written by David Howells (dhowells@redhat.com) 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 9 * 2 of the License, or (at your option) any later version. 10 */ 11 12#include <linux/sched.h> 13#include <linux/signal.h> 14#include <linux/kernel.h> 15#include <linux/mm.h> 16#include <linux/types.h> 17#include <linux/user.h> 18#include <linux/string.h> 19#include <linux/linkage.h> 20#include <linux/init.h> 21#include <linux/module.h> 22 23#include <asm/asm-offsets.h> 24#include <asm/setup.h> 25#include <asm/fpu.h> 26#include <asm/uaccess.h> 27#include <asm/pgtable.h> 28#include <asm/siginfo.h> 29#include <asm/unaligned.h> 30 31void show_backtrace(struct pt_regs *, unsigned long); 32 33extern asmlinkage void __break_hijack_kernel_event(void); 34 35/*****************************************************************************/ 36/* 37 * instruction access error 38 */ 39asmlinkage void insn_access_error(unsigned long esfr1, unsigned long epcr0, unsigned long esr0) 40{ 41 siginfo_t info; 42 43 die_if_kernel("-- Insn Access Error --\n" 44 "EPCR0 : %08lx\n" 45 "ESR0 : %08lx\n", 46 epcr0, esr0); 47 48 info.si_signo = SIGSEGV; 49 info.si_code = SEGV_ACCERR; 50 info.si_errno = 0; 51 info.si_addr = (void __user *) ((epcr0 & EPCR0_V) ? (epcr0 & EPCR0_PC) : __frame->pc); 52 53 force_sig_info(info.si_signo, &info, current); 54} /* end insn_access_error() */ 55 56/*****************************************************************************/ 57/* 58 * handler for: 59 * - illegal instruction 60 * - privileged instruction 61 * - unsupported trap 62 * - debug exceptions 63 */ 64asmlinkage void illegal_instruction(unsigned long esfr1, unsigned long epcr0, unsigned long esr0) 65{ 66 siginfo_t info; 67 68 die_if_kernel("-- Illegal Instruction --\n" 69 "EPCR0 : %08lx\n" 70 "ESR0 : %08lx\n" 71 "ESFR1 : %08lx\n", 72 epcr0, esr0, esfr1); 73 74 info.si_errno = 0; 75 info.si_addr = (void __user *) ((epcr0 & EPCR0_V) ? (epcr0 & EPCR0_PC) : __frame->pc); 76 77 switch (__frame->tbr & TBR_TT) { 78 case TBR_TT_ILLEGAL_INSTR: 79 info.si_signo = SIGILL; 80 info.si_code = ILL_ILLOPC; 81 break; 82 case TBR_TT_PRIV_INSTR: 83 info.si_signo = SIGILL; 84 info.si_code = ILL_PRVOPC; 85 break; 86 case TBR_TT_TRAP2 ... TBR_TT_TRAP126: 87 info.si_signo = SIGILL; 88 info.si_code = ILL_ILLTRP; 89 break; 90 /* GDB uses "tira gr0, #1" as a breakpoint instruction. */ 91 case TBR_TT_TRAP1: 92 case TBR_TT_BREAK: 93 info.si_signo = SIGTRAP; 94 info.si_code = 95 (__frame->__status & REG__STATUS_STEPPED) ? TRAP_TRACE : TRAP_BRKPT; 96 break; 97 } 98 99 force_sig_info(info.si_signo, &info, current); 100} /* end illegal_instruction() */ 101 102/*****************************************************************************/ 103/* 104 * handle atomic operations with errors 105 * - arguments in gr8, gr9, gr10 106 * - original memory value placed in gr5 107 * - replacement memory value placed in gr9 108 */ 109asmlinkage void atomic_operation(unsigned long esfr1, unsigned long epcr0, 110 unsigned long esr0) 111{ 112 static DEFINE_SPINLOCK(atomic_op_lock); 113 unsigned long x, y, z; 114 unsigned long __user *p; 115 mm_segment_t oldfs; 116 siginfo_t info; 117 int ret; 118 119 y = 0; 120 z = 0; 121 122 oldfs = get_fs(); 123 if (!user_mode(__frame)) 124 set_fs(KERNEL_DS); 125 126 switch (__frame->tbr & TBR_TT) { 127 /* TIRA gr0,#120 128 * u32 __atomic_user_cmpxchg32(u32 *ptr, u32 test, u32 new) 129 */ 130 case TBR_TT_ATOMIC_CMPXCHG32: 131 p = (unsigned long __user *) __frame->gr8; 132 x = __frame->gr9; 133 y = __frame->gr10; 134 135 for (;;) { 136 ret = get_user(z, p); 137 if (ret < 0) 138 goto error; 139 140 if (z != x) 141 goto done; 142 143 spin_lock_irq(&atomic_op_lock); 144 145 if (__get_user(z, p) == 0) { 146 if (z != x) 147 goto done2; 148 149 if (__put_user(y, p) == 0) 150 goto done2; 151 goto error2; 152 } 153 154 spin_unlock_irq(&atomic_op_lock); 155 } 156 157 /* TIRA gr0,#121 158 * u32 __atomic_kernel_xchg32(void *v, u32 new) 159 */ 160 case TBR_TT_ATOMIC_XCHG32: 161 p = (unsigned long __user *) __frame->gr8; 162 y = __frame->gr9; 163 164 for (;;) { 165 ret = get_user(z, p); 166 if (ret < 0) 167 goto error; 168 169 spin_lock_irq(&atomic_op_lock); 170 171 if (__get_user(z, p) == 0) { 172 if (__put_user(y, p) == 0) 173 goto done2; 174 goto error2; 175 } 176 177 spin_unlock_irq(&atomic_op_lock); 178 } 179 180 /* TIRA gr0,#122 181 * ulong __atomic_kernel_XOR_return(ulong i, ulong *v) 182 */ 183 case TBR_TT_ATOMIC_XOR: 184 p = (unsigned long __user *) __frame->gr8; 185 x = __frame->gr9; 186 187 for (;;) { 188 ret = get_user(z, p); 189 if (ret < 0) 190 goto error; 191 192 spin_lock_irq(&atomic_op_lock); 193 194 if (__get_user(z, p) == 0) { 195 y = x ^ z; 196 if (__put_user(y, p) == 0) 197 goto done2; 198 goto error2; 199 } 200 201 spin_unlock_irq(&atomic_op_lock); 202 } 203 204 /* TIRA gr0,#123 205 * ulong __atomic_kernel_OR_return(ulong i, ulong *v) 206 */ 207 case TBR_TT_ATOMIC_OR: 208 p = (unsigned long __user *) __frame->gr8; 209 x = __frame->gr9; 210 211 for (;;) { 212 ret = get_user(z, p); 213 if (ret < 0) 214 goto error; 215 216 spin_lock_irq(&atomic_op_lock); 217 218 if (__get_user(z, p) == 0) { 219 y = x ^ z; 220 if (__put_user(y, p) == 0) 221 goto done2; 222 goto error2; 223 } 224 225 spin_unlock_irq(&atomic_op_lock); 226 } 227 228 /* TIRA gr0,#124 229 * ulong __atomic_kernel_AND_return(ulong i, ulong *v) 230 */ 231 case TBR_TT_ATOMIC_AND: 232 p = (unsigned long __user *) __frame->gr8; 233 x = __frame->gr9; 234 235 for (;;) { 236 ret = get_user(z, p); 237 if (ret < 0) 238 goto error; 239 240 spin_lock_irq(&atomic_op_lock); 241 242 if (__get_user(z, p) == 0) { 243 y = x & z; 244 if (__put_user(y, p) == 0) 245 goto done2; 246 goto error2; 247 } 248 249 spin_unlock_irq(&atomic_op_lock); 250 } 251 252 /* TIRA gr0,#125 253 * int __atomic_user_sub_return(atomic_t *v, int i) 254 */ 255 case TBR_TT_ATOMIC_SUB: 256 p = (unsigned long __user *) __frame->gr8; 257 x = __frame->gr9; 258 259 for (;;) { 260 ret = get_user(z, p); 261 if (ret < 0) 262 goto error; 263 264 spin_lock_irq(&atomic_op_lock); 265 266 if (__get_user(z, p) == 0) { 267 y = z - x; 268 if (__put_user(y, p) == 0) 269 goto done2; 270 goto error2; 271 } 272 273 spin_unlock_irq(&atomic_op_lock); 274 } 275 276 /* TIRA gr0,#126 277 * int __atomic_user_add_return(atomic_t *v, int i) 278 */ 279 case TBR_TT_ATOMIC_ADD: 280 p = (unsigned long __user *) __frame->gr8; 281 x = __frame->gr9; 282 283 for (;;) { 284 ret = get_user(z, p); 285 if (ret < 0) 286 goto error; 287 288 spin_lock_irq(&atomic_op_lock); 289 290 if (__get_user(z, p) == 0) { 291 y = z + x; 292 if (__put_user(y, p) == 0) 293 goto done2; 294 goto error2; 295 } 296 297 spin_unlock_irq(&atomic_op_lock); 298 } 299 300 default: 301 BUG(); 302 } 303 304done2: 305 spin_unlock_irq(&atomic_op_lock); 306done: 307 if (!user_mode(__frame)) 308 set_fs(oldfs); 309 __frame->gr5 = z; 310 __frame->gr9 = y; 311 return; 312 313error2: 314 spin_unlock_irq(&atomic_op_lock); 315error: 316 if (!user_mode(__frame)) 317 set_fs(oldfs); 318 __frame->pc -= 4; 319 320 die_if_kernel("-- Atomic Op Error --\n"); 321 322 info.si_signo = SIGSEGV; 323 info.si_code = SEGV_ACCERR; 324 info.si_errno = 0; 325 info.si_addr = (void __user *) __frame->pc; 326 327 force_sig_info(info.si_signo, &info, current); 328} 329 330/*****************************************************************************/ 331/* 332 * 333 */ 334asmlinkage void media_exception(unsigned long msr0, unsigned long msr1) 335{ 336 siginfo_t info; 337 338 die_if_kernel("-- Media Exception --\n" 339 "MSR0 : %08lx\n" 340 "MSR1 : %08lx\n", 341 msr0, msr1); 342 343 info.si_signo = SIGFPE; 344 info.si_code = FPE_MDAOVF; 345 info.si_errno = 0; 346 info.si_addr = (void __user *) __frame->pc; 347 348 force_sig_info(info.si_signo, &info, current); 349} /* end media_exception() */ 350 351/*****************************************************************************/ 352/* 353 * instruction or data access exception 354 */ 355asmlinkage void memory_access_exception(unsigned long esr0, 356 unsigned long ear0, 357 unsigned long epcr0) 358{ 359 siginfo_t info; 360 361#ifdef CONFIG_MMU 362 unsigned long fixup; 363 364 fixup = search_exception_table(__frame->pc); 365 if (fixup) { 366 __frame->pc = fixup; 367 return; 368 } 369#endif 370 371 die_if_kernel("-- Memory Access Exception --\n" 372 "ESR0 : %08lx\n" 373 "EAR0 : %08lx\n" 374 "EPCR0 : %08lx\n", 375 esr0, ear0, epcr0); 376 377 info.si_signo = SIGSEGV; 378 info.si_code = SEGV_ACCERR; 379 info.si_errno = 0; 380 info.si_addr = NULL; 381 382 if ((esr0 & (ESRx_VALID | ESR0_EAV)) == (ESRx_VALID | ESR0_EAV)) 383 info.si_addr = (void __user *) ear0; 384 385 force_sig_info(info.si_signo, &info, current); 386 387} /* end memory_access_exception() */ 388 389/*****************************************************************************/ 390/* 391 * data access error 392 * - double-word data load from CPU control area (0xFExxxxxx) 393 * - read performed on inactive or self-refreshing SDRAM 394 * - error notification from slave device 395 * - misaligned address 396 * - access to out of bounds memory region 397 * - user mode accessing privileged memory region 398 * - write to R/O memory region 399 */ 400asmlinkage void data_access_error(unsigned long esfr1, unsigned long esr15, unsigned long ear15) 401{ 402 siginfo_t info; 403 404 die_if_kernel("-- Data Access Error --\n" 405 "ESR15 : %08lx\n" 406 "EAR15 : %08lx\n", 407 esr15, ear15); 408 409 info.si_signo = SIGSEGV; 410 info.si_code = SEGV_ACCERR; 411 info.si_errno = 0; 412 info.si_addr = (void __user *) 413 (((esr15 & (ESRx_VALID|ESR15_EAV)) == (ESRx_VALID|ESR15_EAV)) ? ear15 : 0); 414 415 force_sig_info(info.si_signo, &info, current); 416} /* end data_access_error() */ 417 418/*****************************************************************************/ 419/* 420 * data store error - should only happen if accessing inactive or self-refreshing SDRAM 421 */ 422asmlinkage void data_store_error(unsigned long esfr1, unsigned long esr15) 423{ 424 die_if_kernel("-- Data Store Error --\n" 425 "ESR15 : %08lx\n", 426 esr15); 427 BUG(); 428} /* end data_store_error() */ 429 430/*****************************************************************************/ 431/* 432 * 433 */ 434asmlinkage void division_exception(unsigned long esfr1, unsigned long esr0, unsigned long isr) 435{ 436 siginfo_t info; 437 438 die_if_kernel("-- Division Exception --\n" 439 "ESR0 : %08lx\n" 440 "ISR : %08lx\n", 441 esr0, isr); 442 443 info.si_signo = SIGFPE; 444 info.si_code = FPE_INTDIV; 445 info.si_errno = 0; 446 info.si_addr = (void __user *) __frame->pc; 447 448 force_sig_info(info.si_signo, &info, current); 449} /* end division_exception() */ 450 451/*****************************************************************************/ 452/* 453 * 454 */ 455asmlinkage void compound_exception(unsigned long esfr1, 456 unsigned long esr0, unsigned long esr14, unsigned long esr15, 457 unsigned long msr0, unsigned long msr1) 458{ 459 die_if_kernel("-- Compound Exception --\n" 460 "ESR0 : %08lx\n" 461 "ESR15 : %08lx\n" 462 "ESR15 : %08lx\n" 463 "MSR0 : %08lx\n" 464 "MSR1 : %08lx\n", 465 esr0, esr14, esr15, msr0, msr1); 466 BUG(); 467} /* end compound_exception() */ 468 469void show_stack(struct task_struct *task, unsigned long *sp) 470{ 471} 472 473void show_trace_task(struct task_struct *tsk) 474{ 475 printk("CONTEXT: stack=0x%lx frame=0x%p LR=0x%lx RET=0x%lx\n", 476 tsk->thread.sp, tsk->thread.frame, tsk->thread.lr, tsk->thread.sched_lr); 477} 478 479static const char *regnames[] = { 480 "PSR ", "ISR ", "CCR ", "CCCR", 481 "LR ", "LCR ", "PC ", "_stt", 482 "sys ", "GR8*", "GNE0", "GNE1", 483 "IACH", "IACL", 484 "TBR ", "SP ", "FP ", "GR3 ", 485 "GR4 ", "GR5 ", "GR6 ", "GR7 ", 486 "GR8 ", "GR9 ", "GR10", "GR11", 487 "GR12", "GR13", "GR14", "GR15", 488 "GR16", "GR17", "GR18", "GR19", 489 "GR20", "GR21", "GR22", "GR23", 490 "GR24", "GR25", "GR26", "GR27", 491 "EFRM", "CURR", "GR30", "BFRM" 492}; 493 494void show_regs(struct pt_regs *regs) 495{ 496 unsigned long *reg; 497 int loop; 498 499 printk("\n"); 500 show_regs_print_info(KERN_DEFAULT); 501 502 printk("Frame: @%08lx [%s]\n", 503 (unsigned long) regs, 504 regs->psr & PSR_S ? "kernel" : "user"); 505 506 reg = (unsigned long *) regs; 507 for (loop = 0; loop < NR_PT_REGS; loop++) { 508 printk("%s %08lx", regnames[loop + 0], reg[loop + 0]); 509 510 if (loop == NR_PT_REGS - 1 || loop % 5 == 4) 511 printk("\n"); 512 else 513 printk(" | "); 514 } 515} 516 517void die_if_kernel(const char *str, ...) 518{ 519 char buffer[256]; 520 va_list va; 521 522 if (user_mode(__frame)) 523 return; 524 525 va_start(va, str); 526 vsnprintf(buffer, sizeof(buffer), str, va); 527 va_end(va); 528 529 console_verbose(); 530 printk("\n===================================\n"); 531 printk("%s\n", buffer); 532 show_backtrace(__frame, 0); 533 534 __break_hijack_kernel_event(); 535 do_exit(SIGSEGV); 536} 537 538/*****************************************************************************/ 539/* 540 * dump the contents of an exception frame 541 */ 542static void show_backtrace_regs(struct pt_regs *frame) 543{ 544 unsigned long *reg; 545 int loop; 546 547 /* print the registers for this frame */ 548 printk("<-- %s Frame: @%p -->\n", 549 frame->psr & PSR_S ? "Kernel Mode" : "User Mode", 550 frame); 551 552 reg = (unsigned long *) frame; 553 for (loop = 0; loop < NR_PT_REGS; loop++) { 554 printk("%s %08lx", regnames[loop + 0], reg[loop + 0]); 555 556 if (loop == NR_PT_REGS - 1 || loop % 5 == 4) 557 printk("\n"); 558 else 559 printk(" | "); 560 } 561 562 printk("--------\n"); 563} /* end show_backtrace_regs() */ 564 565/*****************************************************************************/ 566/* 567 * generate a backtrace of the kernel stack 568 */ 569void show_backtrace(struct pt_regs *frame, unsigned long sp) 570{ 571 struct pt_regs *frame0; 572 unsigned long tos = 0, stop = 0, base; 573 int format; 574 575 base = ((((unsigned long) frame) + 8191) & ~8191) - sizeof(struct user_context); 576 frame0 = (struct pt_regs *) base; 577 578 if (sp) { 579 tos = sp; 580 stop = (unsigned long) frame; 581 } 582 583 printk("\nProcess %s (pid: %d)\n\n", current->comm, current->pid); 584 585 for (;;) { 586 /* dump stack segment between frames */ 587 //printk("%08lx -> %08lx\n", tos, stop); 588 format = 0; 589 while (tos < stop) { 590 if (format == 0) 591 printk(" %04lx :", tos & 0xffff); 592 593 printk(" %08lx", *(unsigned long *) tos); 594 595 tos += 4; 596 format++; 597 if (format == 8) { 598 printk("\n"); 599 format = 0; 600 } 601 } 602 603 if (format > 0) 604 printk("\n"); 605 606 /* dump frame 0 outside of the loop */ 607 if (frame == frame0) 608 break; 609 610 tos = frame->sp; 611 if (((unsigned long) frame) + sizeof(*frame) != tos) { 612 printk("-- TOS %08lx does not follow frame %p --\n", 613 tos, frame); 614 break; 615 } 616 617 show_backtrace_regs(frame); 618 619 /* dump the stack between this frame and the next */ 620 stop = (unsigned long) frame->next_frame; 621 if (stop != base && 622 (stop < tos || 623 stop > base || 624 (stop < base && stop + sizeof(*frame) > base) || 625 stop & 3)) { 626 printk("-- next_frame %08lx is invalid (range %08lx-%08lx) --\n", 627 stop, tos, base); 628 break; 629 } 630 631 /* move to next frame */ 632 frame = frame->next_frame; 633 } 634 635 /* we can always dump frame 0, even if the rest of the stack is corrupt */ 636 show_backtrace_regs(frame0); 637 638} /* end show_backtrace() */ 639 640/*****************************************************************************/ 641/* 642 * initialise traps 643 */ 644void __init trap_init (void) 645{ 646} /* end trap_init() */ 647