blob: 77107838271fb4496d8a668818b28f35b606b33b [file] [log] [blame]
Paul Mundt6b002232006-10-12 17:07:45 +09001/*
2 * 'traps.c' handles hardware traps and faults after we have saved some
3 * state in 'entry.S'.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 *
5 * SuperH version: Copyright (C) 1999 Niibe Yutaka
6 * Copyright (C) 2000 Philipp Rumpf
7 * Copyright (C) 2000 David Howells
Paul Mundt6b002232006-10-12 17:07:45 +09008 * Copyright (C) 2002 - 2006 Paul Mundt
9 *
10 * This file is subject to the terms and conditions of the GNU General Public
11 * License. See the file "COPYING" in the main directory of this archive
12 * for more details.
Linus Torvalds1da177e2005-04-16 15:20:36 -070013 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/ptrace.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include <linux/init.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <linux/spinlock.h>
18#include <linux/module.h>
19#include <linux/kallsyms.h>
Paul Mundt1f666582006-10-19 16:20:25 +090020#include <linux/io.h>
Paul Mundtfa691512007-03-08 19:41:21 +090021#include <linux/bug.h>
Paul Mundt9b8c90e2006-12-06 11:07:51 +090022#include <linux/debug_locks.h>
Paul Mundtdc34d312006-12-08 17:41:43 +090023#include <linux/limits.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#include <asm/system.h>
25#include <asm/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026
27#ifdef CONFIG_SH_KGDB
28#include <asm/kgdb.h>
Stuart Menefyf0bc8142006-11-21 11:16:57 +090029#define CHK_REMOTE_DEBUG(regs) \
30{ \
Takashi YOSHII4b565682006-09-27 17:15:32 +090031 if (kgdb_debug_hook && !user_mode(regs))\
32 (*kgdb_debug_hook)(regs); \
Linus Torvalds1da177e2005-04-16 15:20:36 -070033}
34#else
35#define CHK_REMOTE_DEBUG(regs)
36#endif
37
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#ifdef CONFIG_CPU_SH2
Yoshinori Sato0983b312006-11-05 15:58:47 +090039# define TRAP_RESERVED_INST 4
40# define TRAP_ILLEGAL_SLOT_INST 6
41# define TRAP_ADDRESS_ERROR 9
42# ifdef CONFIG_CPU_SH2A
43# define TRAP_DIVZERO_ERROR 17
44# define TRAP_DIVOVF_ERROR 18
45# endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070046#else
47#define TRAP_RESERVED_INST 12
48#define TRAP_ILLEGAL_SLOT_INST 13
49#endif
50
Paul Mundt6b002232006-10-12 17:07:45 +090051static void dump_mem(const char *str, unsigned long bottom, unsigned long top)
52{
53 unsigned long p;
54 int i;
55
56 printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top);
57
58 for (p = bottom & ~31; p < top; ) {
59 printk("%04lx: ", p & 0xffff);
60
61 for (i = 0; i < 8; i++, p += 4) {
62 unsigned int val;
63
64 if (p < bottom || p >= top)
65 printk(" ");
66 else {
67 if (__get_user(val, (unsigned int __user *)p)) {
68 printk("\n");
69 return;
70 }
71 printk("%08x ", val);
72 }
73 }
74 printk("\n");
75 }
76}
Linus Torvalds1da177e2005-04-16 15:20:36 -070077
Paul Mundt765ae312006-09-27 11:31:32 +090078DEFINE_SPINLOCK(die_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
80void die(const char * str, struct pt_regs * regs, long err)
81{
82 static int die_counter;
83
84 console_verbose();
85 spin_lock_irq(&die_lock);
Paul Mundt6b002232006-10-12 17:07:45 +090086 bust_spinlocks(1);
87
Linus Torvalds1da177e2005-04-16 15:20:36 -070088 printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
Paul Mundt6b002232006-10-12 17:07:45 +090089
Linus Torvalds1da177e2005-04-16 15:20:36 -070090 CHK_REMOTE_DEBUG(regs);
Paul Mundt6b002232006-10-12 17:07:45 +090091 print_modules();
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 show_regs(regs);
Paul Mundt6b002232006-10-12 17:07:45 +090093
94 printk("Process: %s (pid: %d, stack limit = %p)\n",
95 current->comm, current->pid, task_stack_page(current) + 1);
96
97 if (!user_mode(regs) || in_interrupt())
98 dump_mem("Stack: ", regs->regs[15], THREAD_SIZE +
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +090099 (unsigned long)task_stack_page(current));
Paul Mundt6b002232006-10-12 17:07:45 +0900100
101 bust_spinlocks(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 spin_unlock_irq(&die_lock);
103 do_exit(SIGSEGV);
104}
105
Paul Mundt6b002232006-10-12 17:07:45 +0900106static inline void die_if_kernel(const char *str, struct pt_regs *regs,
107 long err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108{
109 if (!user_mode(regs))
110 die(str, regs, err);
111}
112
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113/*
114 * try and fix up kernelspace address errors
115 * - userspace errors just cause EFAULT to be returned, resulting in SEGV
116 * - kernel/userspace interfaces cause a jump to an appropriate handler
117 * - other kernel errors are bad
118 * - return 0 if fixed-up, -EFAULT if non-fatal (to the kernel) fault
119 */
120static int die_if_no_fixup(const char * str, struct pt_regs * regs, long err)
121{
Paul Mundt6b002232006-10-12 17:07:45 +0900122 if (!user_mode(regs)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 const struct exception_table_entry *fixup;
124 fixup = search_exception_tables(regs->pc);
125 if (fixup) {
126 regs->pc = fixup->fixup;
127 return 0;
128 }
129 die(str, regs, err);
130 }
131 return -EFAULT;
132}
133
134/*
135 * handle an instruction that does an unaligned memory access by emulating the
136 * desired behaviour
137 * - note that PC _may not_ point to the faulting instruction
138 * (if that instruction is in a branch delay slot)
139 * - return 0 if emulation okay, -EFAULT on existential error
140 */
141static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs)
142{
143 int ret, index, count;
144 unsigned long *rm, *rn;
145 unsigned char *src, *dst;
146
147 index = (instruction>>8)&15; /* 0x0F00 */
148 rn = &regs->regs[index];
149
150 index = (instruction>>4)&15; /* 0x00F0 */
151 rm = &regs->regs[index];
152
153 count = 1<<(instruction&3);
154
155 ret = -EFAULT;
156 switch (instruction>>12) {
157 case 0: /* mov.[bwl] to/from memory via r0+rn */
158 if (instruction & 8) {
159 /* from memory */
160 src = (unsigned char*) *rm;
161 src += regs->regs[0];
162 dst = (unsigned char*) rn;
163 *(unsigned long*)dst = 0;
164
165#ifdef __LITTLE_ENDIAN__
166 if (copy_from_user(dst, src, count))
167 goto fetch_fault;
168
169 if ((count == 2) && dst[1] & 0x80) {
170 dst[2] = 0xff;
171 dst[3] = 0xff;
172 }
173#else
174 dst += 4-count;
175
176 if (__copy_user(dst, src, count))
177 goto fetch_fault;
178
179 if ((count == 2) && dst[2] & 0x80) {
180 dst[0] = 0xff;
181 dst[1] = 0xff;
182 }
183#endif
184 } else {
185 /* to memory */
186 src = (unsigned char*) rm;
187#if !defined(__LITTLE_ENDIAN__)
188 src += 4-count;
189#endif
190 dst = (unsigned char*) *rn;
191 dst += regs->regs[0];
192
193 if (copy_to_user(dst, src, count))
194 goto fetch_fault;
195 }
196 ret = 0;
197 break;
198
199 case 1: /* mov.l Rm,@(disp,Rn) */
200 src = (unsigned char*) rm;
201 dst = (unsigned char*) *rn;
202 dst += (instruction&0x000F)<<2;
203
204 if (copy_to_user(dst,src,4))
205 goto fetch_fault;
206 ret = 0;
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900207 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208
209 case 2: /* mov.[bwl] to memory, possibly with pre-decrement */
210 if (instruction & 4)
211 *rn -= count;
212 src = (unsigned char*) rm;
213 dst = (unsigned char*) *rn;
214#if !defined(__LITTLE_ENDIAN__)
215 src += 4-count;
216#endif
217 if (copy_to_user(dst, src, count))
218 goto fetch_fault;
219 ret = 0;
220 break;
221
222 case 5: /* mov.l @(disp,Rm),Rn */
223 src = (unsigned char*) *rm;
224 src += (instruction&0x000F)<<2;
225 dst = (unsigned char*) rn;
226 *(unsigned long*)dst = 0;
227
228 if (copy_from_user(dst,src,4))
229 goto fetch_fault;
230 ret = 0;
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900231 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232
233 case 6: /* mov.[bwl] from memory, possibly with post-increment */
234 src = (unsigned char*) *rm;
235 if (instruction & 4)
236 *rm += count;
237 dst = (unsigned char*) rn;
238 *(unsigned long*)dst = 0;
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900239
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240#ifdef __LITTLE_ENDIAN__
241 if (copy_from_user(dst, src, count))
242 goto fetch_fault;
243
244 if ((count == 2) && dst[1] & 0x80) {
245 dst[2] = 0xff;
246 dst[3] = 0xff;
247 }
248#else
249 dst += 4-count;
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900250
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 if (copy_from_user(dst, src, count))
252 goto fetch_fault;
253
254 if ((count == 2) && dst[2] & 0x80) {
255 dst[0] = 0xff;
256 dst[1] = 0xff;
257 }
258#endif
259 ret = 0;
260 break;
261
262 case 8:
263 switch ((instruction&0xFF00)>>8) {
264 case 0x81: /* mov.w R0,@(disp,Rn) */
265 src = (unsigned char*) &regs->regs[0];
266#if !defined(__LITTLE_ENDIAN__)
267 src += 2;
268#endif
269 dst = (unsigned char*) *rm; /* called Rn in the spec */
270 dst += (instruction&0x000F)<<1;
271
272 if (copy_to_user(dst, src, 2))
273 goto fetch_fault;
274 ret = 0;
275 break;
276
277 case 0x85: /* mov.w @(disp,Rm),R0 */
278 src = (unsigned char*) *rm;
279 src += (instruction&0x000F)<<1;
280 dst = (unsigned char*) &regs->regs[0];
281 *(unsigned long*)dst = 0;
282
283#if !defined(__LITTLE_ENDIAN__)
284 dst += 2;
285#endif
286
287 if (copy_from_user(dst, src, 2))
288 goto fetch_fault;
289
290#ifdef __LITTLE_ENDIAN__
291 if (dst[1] & 0x80) {
292 dst[2] = 0xff;
293 dst[3] = 0xff;
294 }
295#else
296 if (dst[2] & 0x80) {
297 dst[0] = 0xff;
298 dst[1] = 0xff;
299 }
300#endif
301 ret = 0;
302 break;
303 }
304 break;
305 }
306 return ret;
307
308 fetch_fault:
309 /* Argh. Address not only misaligned but also non-existent.
310 * Raise an EFAULT and see if it's trapped
311 */
312 return die_if_no_fixup("Fault in unaligned fixup", regs, 0);
313}
314
315/*
316 * emulate the instruction in the delay slot
317 * - fetches the instruction from PC+2
318 */
319static inline int handle_unaligned_delayslot(struct pt_regs *regs)
320{
321 u16 instruction;
322
323 if (copy_from_user(&instruction, (u16 *)(regs->pc+2), 2)) {
324 /* the instruction-fetch faulted */
325 if (user_mode(regs))
326 return -EFAULT;
327
328 /* kernel */
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900329 die("delay-slot-insn faulting in handle_unaligned_delayslot",
330 regs, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 }
332
333 return handle_unaligned_ins(instruction,regs);
334}
335
336/*
337 * handle an instruction that does an unaligned memory access
338 * - have to be careful of branch delay-slot instructions that fault
339 * SH3:
340 * - if the branch would be taken PC points to the branch
341 * - if the branch would not be taken, PC points to delay-slot
342 * SH4:
343 * - PC always points to delayed branch
344 * - return 0 if handled, -EFAULT if failed (may not return if in kernel)
345 */
346
347/* Macros to determine offset from current PC for branch instructions */
348/* Explicit type coercion is used to force sign extension where needed */
349#define SH_PC_8BIT_OFFSET(instr) ((((signed char)(instr))*2) + 4)
350#define SH_PC_12BIT_OFFSET(instr) ((((signed short)(instr<<4))>>3) + 4)
351
Paul Mundt710ee0c2006-11-05 16:48:42 +0900352/*
353 * XXX: SH-2A needs this too, but it needs an overhaul thanks to mixed 32-bit
354 * opcodes..
355 */
356#ifndef CONFIG_CPU_SH2A
357static int handle_unaligned_notify_count = 10;
358
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
360{
361 u_int rm;
362 int ret, index;
363
364 index = (instruction>>8)&15; /* 0x0F00 */
365 rm = regs->regs[index];
366
367 /* shout about the first ten userspace fixups */
368 if (user_mode(regs) && handle_unaligned_notify_count>0) {
369 handle_unaligned_notify_count--;
370
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900371 printk(KERN_NOTICE "Fixing up unaligned userspace access "
372 "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 current->comm,current->pid,(u16*)regs->pc,instruction);
374 }
375
376 ret = -EFAULT;
377 switch (instruction&0xF000) {
378 case 0x0000:
379 if (instruction==0x000B) {
380 /* rts */
381 ret = handle_unaligned_delayslot(regs);
382 if (ret==0)
383 regs->pc = regs->pr;
384 }
385 else if ((instruction&0x00FF)==0x0023) {
386 /* braf @Rm */
387 ret = handle_unaligned_delayslot(regs);
388 if (ret==0)
389 regs->pc += rm + 4;
390 }
391 else if ((instruction&0x00FF)==0x0003) {
392 /* bsrf @Rm */
393 ret = handle_unaligned_delayslot(regs);
394 if (ret==0) {
395 regs->pr = regs->pc + 4;
396 regs->pc += rm + 4;
397 }
398 }
399 else {
400 /* mov.[bwl] to/from memory via r0+rn */
401 goto simple;
402 }
403 break;
404
405 case 0x1000: /* mov.l Rm,@(disp,Rn) */
406 goto simple;
407
408 case 0x2000: /* mov.[bwl] to memory, possibly with pre-decrement */
409 goto simple;
410
411 case 0x4000:
412 if ((instruction&0x00FF)==0x002B) {
413 /* jmp @Rm */
414 ret = handle_unaligned_delayslot(regs);
415 if (ret==0)
416 regs->pc = rm;
417 }
418 else if ((instruction&0x00FF)==0x000B) {
419 /* jsr @Rm */
420 ret = handle_unaligned_delayslot(regs);
421 if (ret==0) {
422 regs->pr = regs->pc + 4;
423 regs->pc = rm;
424 }
425 }
426 else {
427 /* mov.[bwl] to/from memory via r0+rn */
428 goto simple;
429 }
430 break;
431
432 case 0x5000: /* mov.l @(disp,Rm),Rn */
433 goto simple;
434
435 case 0x6000: /* mov.[bwl] from memory, possibly with post-increment */
436 goto simple;
437
438 case 0x8000: /* bf lab, bf/s lab, bt lab, bt/s lab */
439 switch (instruction&0x0F00) {
440 case 0x0100: /* mov.w R0,@(disp,Rm) */
441 goto simple;
442 case 0x0500: /* mov.w @(disp,Rm),R0 */
443 goto simple;
444 case 0x0B00: /* bf lab - no delayslot*/
445 break;
446 case 0x0F00: /* bf/s lab */
447 ret = handle_unaligned_delayslot(regs);
448 if (ret==0) {
449#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)
450 if ((regs->sr & 0x00000001) != 0)
451 regs->pc += 4; /* next after slot */
452 else
453#endif
454 regs->pc += SH_PC_8BIT_OFFSET(instruction);
455 }
456 break;
457 case 0x0900: /* bt lab - no delayslot */
458 break;
459 case 0x0D00: /* bt/s lab */
460 ret = handle_unaligned_delayslot(regs);
461 if (ret==0) {
462#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)
463 if ((regs->sr & 0x00000001) == 0)
464 regs->pc += 4; /* next after slot */
465 else
466#endif
467 regs->pc += SH_PC_8BIT_OFFSET(instruction);
468 }
469 break;
470 }
471 break;
472
473 case 0xA000: /* bra label */
474 ret = handle_unaligned_delayslot(regs);
475 if (ret==0)
476 regs->pc += SH_PC_12BIT_OFFSET(instruction);
477 break;
478
479 case 0xB000: /* bsr label */
480 ret = handle_unaligned_delayslot(regs);
481 if (ret==0) {
482 regs->pr = regs->pc + 4;
483 regs->pc += SH_PC_12BIT_OFFSET(instruction);
484 }
485 break;
486 }
487 return ret;
488
489 /* handle non-delay-slot instruction */
490 simple:
491 ret = handle_unaligned_ins(instruction,regs);
492 if (ret==0)
493 regs->pc += 2;
494 return ret;
495}
Paul Mundt710ee0c2006-11-05 16:48:42 +0900496#endif /* CONFIG_CPU_SH2A */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497
Yoshinori Sato0983b312006-11-05 15:58:47 +0900498#ifdef CONFIG_CPU_HAS_SR_RB
499#define lookup_exception_vector(x) \
500 __asm__ __volatile__ ("stc r2_bank, %0\n\t" : "=r" ((x)))
501#else
502#define lookup_exception_vector(x) \
503 __asm__ __volatile__ ("mov r4, %0\n\t" : "=r" ((x)))
504#endif
505
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506/*
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900507 * Handle various address error exceptions:
508 * - instruction address error:
509 * misaligned PC
510 * PC >= 0x80000000 in user mode
511 * - data address error (read and write)
512 * misaligned data access
513 * access to >= 0x80000000 is user mode
514 * Unfortuntaly we can't distinguish between instruction address error
515 * and data address errors caused by read acceses.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 */
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900517asmlinkage void do_address_error(struct pt_regs *regs,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 unsigned long writeaccess,
519 unsigned long address)
520{
Yoshinori Sato0983b312006-11-05 15:58:47 +0900521 unsigned long error_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 mm_segment_t oldfs;
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900523 siginfo_t info;
Paul Mundt710ee0c2006-11-05 16:48:42 +0900524#ifndef CONFIG_CPU_SH2A
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 u16 instruction;
526 int tmp;
Paul Mundt710ee0c2006-11-05 16:48:42 +0900527#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528
Yoshinori Sato0983b312006-11-05 15:58:47 +0900529 /* Intentional ifdef */
530#ifdef CONFIG_CPU_HAS_SR_RB
531 lookup_exception_vector(error_code);
532#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533
534 oldfs = get_fs();
535
536 if (user_mode(regs)) {
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900537 int si_code = BUS_ADRERR;
538
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 local_irq_enable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540
541 /* bad PC is not something we can fix */
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900542 if (regs->pc & 1) {
543 si_code = BUS_ADRALN;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 goto uspace_segv;
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900545 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546
Yoshinori Sato0983b312006-11-05 15:58:47 +0900547#ifndef CONFIG_CPU_SH2A
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 set_fs(USER_DS);
549 if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) {
550 /* Argh. Fault on the instruction itself.
551 This should never happen non-SMP
552 */
553 set_fs(oldfs);
554 goto uspace_segv;
555 }
556
557 tmp = handle_unaligned_access(instruction, regs);
558 set_fs(oldfs);
559
560 if (tmp==0)
561 return; /* sorted */
Yoshinori Sato0983b312006-11-05 15:58:47 +0900562#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900564uspace_segv:
565 printk(KERN_NOTICE "Sending SIGBUS to \"%s\" due to unaligned "
566 "access (PC %lx PR %lx)\n", current->comm, regs->pc,
567 regs->pr);
568
569 info.si_signo = SIGBUS;
570 info.si_errno = 0;
571 info.si_code = si_code;
572 info.si_addr = (void *) address;
573 force_sig_info(SIGBUS, &info, current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 } else {
575 if (regs->pc & 1)
576 die("unaligned program counter", regs, error_code);
577
Yoshinori Sato0983b312006-11-05 15:58:47 +0900578#ifndef CONFIG_CPU_SH2A
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 set_fs(KERNEL_DS);
580 if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) {
581 /* Argh. Fault on the instruction itself.
582 This should never happen non-SMP
583 */
584 set_fs(oldfs);
585 die("insn faulting in do_address_error", regs, 0);
586 }
587
588 handle_unaligned_access(instruction, regs);
589 set_fs(oldfs);
Yoshinori Sato0983b312006-11-05 15:58:47 +0900590#else
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900591 printk(KERN_NOTICE "Killing process \"%s\" due to unaligned "
592 "access\n", current->comm);
593
Yoshinori Sato0983b312006-11-05 15:58:47 +0900594 force_sig(SIGSEGV, current);
595#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 }
597}
598
599#ifdef CONFIG_SH_DSP
600/*
601 * SH-DSP support gerg@snapgear.com.
602 */
603int is_dsp_inst(struct pt_regs *regs)
604{
605 unsigned short inst;
606
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900607 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 * Safe guard if DSP mode is already enabled or we're lacking
609 * the DSP altogether.
610 */
Paul Mundt11c19652006-12-25 10:19:56 +0900611 if (!(current_cpu_data.flags & CPU_HAS_DSP) || (regs->sr & SR_DSP))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 return 0;
613
614 get_user(inst, ((unsigned short *) regs->pc));
615
616 inst &= 0xf000;
617
618 /* Check for any type of DSP or support instruction */
619 if ((inst == 0xf000) || (inst == 0x4000))
620 return 1;
621
622 return 0;
623}
624#else
625#define is_dsp_inst(regs) (0)
626#endif /* CONFIG_SH_DSP */
627
Yoshinori Sato0983b312006-11-05 15:58:47 +0900628#ifdef CONFIG_CPU_SH2A
629asmlinkage void do_divide_error(unsigned long r4, unsigned long r5,
630 unsigned long r6, unsigned long r7,
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900631 struct pt_regs __regs)
Yoshinori Sato0983b312006-11-05 15:58:47 +0900632{
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900633 struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
Yoshinori Sato0983b312006-11-05 15:58:47 +0900634 siginfo_t info;
635
Yoshinori Sato0983b312006-11-05 15:58:47 +0900636 switch (r4) {
637 case TRAP_DIVZERO_ERROR:
638 info.si_code = FPE_INTDIV;
639 break;
640 case TRAP_DIVOVF_ERROR:
641 info.si_code = FPE_INTOVF;
642 break;
643 }
644
645 force_sig_info(SIGFPE, &info, current);
646}
647#endif
648
Paul Mundt1f666582006-10-19 16:20:25 +0900649/* arch/sh/kernel/cpu/sh4/fpu.c */
650extern int do_fpu_inst(unsigned short, struct pt_regs *);
651extern asmlinkage void do_fpu_state_restore(unsigned long r4, unsigned long r5,
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900652 unsigned long r6, unsigned long r7, struct pt_regs __regs);
Takashi YOSHII4b565682006-09-27 17:15:32 +0900653
654asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5,
655 unsigned long r6, unsigned long r7,
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900656 struct pt_regs __regs)
Takashi YOSHII4b565682006-09-27 17:15:32 +0900657{
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900658 struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
Takashi YOSHII4b565682006-09-27 17:15:32 +0900659 unsigned long error_code;
660 struct task_struct *tsk = current;
661
662#ifdef CONFIG_SH_FPU_EMU
Yoshinori Sato0983b312006-11-05 15:58:47 +0900663 unsigned short inst = 0;
Takashi YOSHII4b565682006-09-27 17:15:32 +0900664 int err;
665
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900666 get_user(inst, (unsigned short*)regs->pc);
Takashi YOSHII4b565682006-09-27 17:15:32 +0900667
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900668 err = do_fpu_inst(inst, regs);
Takashi YOSHII4b565682006-09-27 17:15:32 +0900669 if (!err) {
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900670 regs->pc += 2;
Takashi YOSHII4b565682006-09-27 17:15:32 +0900671 return;
672 }
673 /* not a FPU inst. */
674#endif
675
676#ifdef CONFIG_SH_DSP
677 /* Check if it's a DSP instruction */
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900678 if (is_dsp_inst(regs)) {
Takashi YOSHII4b565682006-09-27 17:15:32 +0900679 /* Enable DSP mode, and restart instruction. */
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900680 regs->sr |= SR_DSP;
Takashi YOSHII4b565682006-09-27 17:15:32 +0900681 return;
682 }
683#endif
684
Yoshinori Sato0983b312006-11-05 15:58:47 +0900685 lookup_exception_vector(error_code);
686
Takashi YOSHII4b565682006-09-27 17:15:32 +0900687 local_irq_enable();
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900688 CHK_REMOTE_DEBUG(regs);
Takashi YOSHII4b565682006-09-27 17:15:32 +0900689 force_sig(SIGILL, tsk);
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900690 die_if_no_fixup("reserved instruction", regs, error_code);
Takashi YOSHII4b565682006-09-27 17:15:32 +0900691}
692
693#ifdef CONFIG_SH_FPU_EMU
694static int emulate_branch(unsigned short inst, struct pt_regs* regs)
695{
696 /*
697 * bfs: 8fxx: PC+=d*2+4;
698 * bts: 8dxx: PC+=d*2+4;
699 * bra: axxx: PC+=D*2+4;
700 * bsr: bxxx: PC+=D*2+4 after PR=PC+4;
701 * braf:0x23: PC+=Rn*2+4;
702 * bsrf:0x03: PC+=Rn*2+4 after PR=PC+4;
703 * jmp: 4x2b: PC=Rn;
704 * jsr: 4x0b: PC=Rn after PR=PC+4;
705 * rts: 000b: PC=PR;
706 */
707 if ((inst & 0xfd00) == 0x8d00) {
708 regs->pc += SH_PC_8BIT_OFFSET(inst);
709 return 0;
710 }
711
712 if ((inst & 0xe000) == 0xa000) {
713 regs->pc += SH_PC_12BIT_OFFSET(inst);
714 return 0;
715 }
716
717 if ((inst & 0xf0df) == 0x0003) {
718 regs->pc += regs->regs[(inst & 0x0f00) >> 8] + 4;
719 return 0;
720 }
721
722 if ((inst & 0xf0df) == 0x400b) {
723 regs->pc = regs->regs[(inst & 0x0f00) >> 8];
724 return 0;
725 }
726
727 if ((inst & 0xffff) == 0x000b) {
728 regs->pc = regs->pr;
729 return 0;
730 }
731
732 return 1;
733}
734#endif
735
736asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5,
737 unsigned long r6, unsigned long r7,
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900738 struct pt_regs __regs)
Takashi YOSHII4b565682006-09-27 17:15:32 +0900739{
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900740 struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
Takashi YOSHII4b565682006-09-27 17:15:32 +0900741 unsigned long error_code;
742 struct task_struct *tsk = current;
743#ifdef CONFIG_SH_FPU_EMU
Yoshinori Sato0983b312006-11-05 15:58:47 +0900744 unsigned short inst = 0;
Takashi YOSHII4b565682006-09-27 17:15:32 +0900745
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900746 get_user(inst, (unsigned short *)regs->pc + 1);
747 if (!do_fpu_inst(inst, regs)) {
748 get_user(inst, (unsigned short *)regs->pc);
749 if (!emulate_branch(inst, regs))
Takashi YOSHII4b565682006-09-27 17:15:32 +0900750 return;
751 /* fault in branch.*/
752 }
753 /* not a FPU inst. */
754#endif
755
Yoshinori Sato0983b312006-11-05 15:58:47 +0900756 lookup_exception_vector(error_code);
757
Takashi YOSHII4b565682006-09-27 17:15:32 +0900758 local_irq_enable();
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900759 CHK_REMOTE_DEBUG(regs);
Takashi YOSHII4b565682006-09-27 17:15:32 +0900760 force_sig(SIGILL, tsk);
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900761 die_if_no_fixup("illegal slot instruction", regs, error_code);
Takashi YOSHII4b565682006-09-27 17:15:32 +0900762}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763
764asmlinkage void do_exception_error(unsigned long r4, unsigned long r5,
765 unsigned long r6, unsigned long r7,
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900766 struct pt_regs __regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767{
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900768 struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 long ex;
Yoshinori Sato0983b312006-11-05 15:58:47 +0900770
771 lookup_exception_vector(ex);
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900772 die_if_kernel("exception", regs, ex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773}
774
775#if defined(CONFIG_SH_STANDARD_BIOS)
776void *gdb_vbr_vector;
777
778static inline void __init gdb_vbr_init(void)
779{
780 register unsigned long vbr;
781
782 /*
783 * Read the old value of the VBR register to initialise
784 * the vector through which debug and BIOS traps are
785 * delegated by the Linux trap handler.
786 */
787 asm volatile("stc vbr, %0" : "=r" (vbr));
788
789 gdb_vbr_vector = (void *)(vbr + 0x100);
790 printk("Setting GDB trap vector to 0x%08lx\n",
791 (unsigned long)gdb_vbr_vector);
792}
793#endif
794
795void __init per_cpu_trap_init(void)
796{
797 extern void *vbr_base;
798
799#ifdef CONFIG_SH_STANDARD_BIOS
800 gdb_vbr_init();
801#endif
802
803 /* NOTE: The VBR value should be at P1
804 (or P2, virtural "fixed" address space).
805 It's definitely should not in physical address. */
806
807 asm volatile("ldc %0, vbr"
808 : /* no output */
809 : "r" (&vbr_base)
810 : "memory");
811}
812
Paul Mundt1f666582006-10-19 16:20:25 +0900813void *set_exception_table_vec(unsigned int vec, void *handler)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814{
815 extern void *exception_handling_table[];
Paul Mundt1f666582006-10-19 16:20:25 +0900816 void *old_handler;
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900817
Paul Mundt1f666582006-10-19 16:20:25 +0900818 old_handler = exception_handling_table[vec];
819 exception_handling_table[vec] = handler;
820 return old_handler;
821}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822
Yoshinori Sato0983b312006-11-05 15:58:47 +0900823extern asmlinkage void address_error_handler(unsigned long r4, unsigned long r5,
824 unsigned long r6, unsigned long r7,
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900825 struct pt_regs __regs);
Yoshinori Sato0983b312006-11-05 15:58:47 +0900826
Paul Mundt1f666582006-10-19 16:20:25 +0900827void __init trap_init(void)
828{
829 set_exception_table_vec(TRAP_RESERVED_INST, do_reserved_inst);
830 set_exception_table_vec(TRAP_ILLEGAL_SLOT_INST, do_illegal_slot_inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831
Takashi YOSHII4b565682006-09-27 17:15:32 +0900832#if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SH_FPU) || \
833 defined(CONFIG_SH_FPU_EMU)
834 /*
835 * For SH-4 lacking an FPU, treat floating point instructions as
836 * reserved. They'll be handled in the math-emu case, or faulted on
837 * otherwise.
838 */
Paul Mundt1f666582006-10-19 16:20:25 +0900839 set_exception_table_evt(0x800, do_reserved_inst);
840 set_exception_table_evt(0x820, do_illegal_slot_inst);
841#elif defined(CONFIG_SH_FPU)
842 set_exception_table_evt(0x800, do_fpu_state_restore);
843 set_exception_table_evt(0x820, do_fpu_state_restore);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844#endif
Yoshinori Sato0983b312006-11-05 15:58:47 +0900845
846#ifdef CONFIG_CPU_SH2
847 set_exception_table_vec(TRAP_ADDRESS_ERROR, address_error_handler);
848#endif
849#ifdef CONFIG_CPU_SH2A
850 set_exception_table_vec(TRAP_DIVZERO_ERROR, do_divide_error);
851 set_exception_table_vec(TRAP_DIVOVF_ERROR, do_divide_error);
852#endif
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900853
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 /* Setup VBR for boot cpu */
855 per_cpu_trap_init();
856}
857
Paul Mundtfa691512007-03-08 19:41:21 +0900858#ifdef CONFIG_BUG
859void handle_BUG(struct pt_regs *regs)
860{
861 enum bug_trap_type tt;
862 tt = report_bug(regs->pc);
863 if (tt == BUG_TRAP_TYPE_WARN) {
864 regs->pc += 2;
865 return;
866 }
867
868 die("Kernel BUG", regs, TRAPA_BUG_OPCODE & 0xff);
869}
870
871int is_valid_bugaddr(unsigned long addr)
872{
873 return addr >= PAGE_OFFSET;
874}
875#endif
876
Paul Mundt6b002232006-10-12 17:07:45 +0900877void show_trace(struct task_struct *tsk, unsigned long *sp,
878 struct pt_regs *regs)
879{
880 unsigned long addr;
881
882 if (regs && user_mode(regs))
883 return;
884
885 printk("\nCall trace: ");
886#ifdef CONFIG_KALLSYMS
887 printk("\n");
888#endif
889
890 while (!kstack_end(sp)) {
891 addr = *sp++;
892 if (kernel_text_address(addr))
893 print_ip_sym(addr);
894 }
895
896 printk("\n");
Paul Mundt9b8c90e2006-12-06 11:07:51 +0900897
898 if (!tsk)
899 tsk = current;
900
901 debug_show_held_locks(tsk);
Paul Mundt6b002232006-10-12 17:07:45 +0900902}
903
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904void show_stack(struct task_struct *tsk, unsigned long *sp)
905{
Paul Mundt6b002232006-10-12 17:07:45 +0900906 unsigned long stack;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907
Paul Mundta6a311392006-09-27 18:22:14 +0900908 if (!tsk)
909 tsk = current;
910 if (tsk == current)
911 sp = (unsigned long *)current_stack_pointer;
912 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 sp = (unsigned long *)tsk->thread.sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914
Paul Mundt6b002232006-10-12 17:07:45 +0900915 stack = (unsigned long)sp;
916 dump_mem("Stack: ", stack, THREAD_SIZE +
917 (unsigned long)task_stack_page(tsk));
918 show_trace(tsk, sp, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919}
920
921void dump_stack(void)
922{
923 show_stack(NULL, NULL);
924}
925EXPORT_SYMBOL(dump_stack);