blob: 3762d9dc20466a026720b1e2821e3c7a4aef8db8 [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 Mundt9b8c90e2006-12-06 11:07:51 +090021#include <linux/debug_locks.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070022#include <asm/system.h>
23#include <asm/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070024
25#ifdef CONFIG_SH_KGDB
26#include <asm/kgdb.h>
Stuart Menefyf0bc8142006-11-21 11:16:57 +090027#define CHK_REMOTE_DEBUG(regs) \
28{ \
Takashi YOSHII4b565682006-09-27 17:15:32 +090029 if (kgdb_debug_hook && !user_mode(regs))\
30 (*kgdb_debug_hook)(regs); \
Linus Torvalds1da177e2005-04-16 15:20:36 -070031}
32#else
33#define CHK_REMOTE_DEBUG(regs)
34#endif
35
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#ifdef CONFIG_CPU_SH2
Yoshinori Sato0983b312006-11-05 15:58:47 +090037# define TRAP_RESERVED_INST 4
38# define TRAP_ILLEGAL_SLOT_INST 6
39# define TRAP_ADDRESS_ERROR 9
40# ifdef CONFIG_CPU_SH2A
41# define TRAP_DIVZERO_ERROR 17
42# define TRAP_DIVOVF_ERROR 18
43# endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#else
45#define TRAP_RESERVED_INST 12
46#define TRAP_ILLEGAL_SLOT_INST 13
47#endif
48
Paul Mundt6b002232006-10-12 17:07:45 +090049static void dump_mem(const char *str, unsigned long bottom, unsigned long top)
50{
51 unsigned long p;
52 int i;
53
54 printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top);
55
56 for (p = bottom & ~31; p < top; ) {
57 printk("%04lx: ", p & 0xffff);
58
59 for (i = 0; i < 8; i++, p += 4) {
60 unsigned int val;
61
62 if (p < bottom || p >= top)
63 printk(" ");
64 else {
65 if (__get_user(val, (unsigned int __user *)p)) {
66 printk("\n");
67 return;
68 }
69 printk("%08x ", val);
70 }
71 }
72 printk("\n");
73 }
74}
Linus Torvalds1da177e2005-04-16 15:20:36 -070075
Paul Mundt765ae312006-09-27 11:31:32 +090076DEFINE_SPINLOCK(die_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070077
78void die(const char * str, struct pt_regs * regs, long err)
79{
80 static int die_counter;
81
82 console_verbose();
83 spin_lock_irq(&die_lock);
Paul Mundt6b002232006-10-12 17:07:45 +090084 bust_spinlocks(1);
85
Linus Torvalds1da177e2005-04-16 15:20:36 -070086 printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
Paul Mundt6b002232006-10-12 17:07:45 +090087
Linus Torvalds1da177e2005-04-16 15:20:36 -070088 CHK_REMOTE_DEBUG(regs);
Paul Mundt6b002232006-10-12 17:07:45 +090089 print_modules();
Linus Torvalds1da177e2005-04-16 15:20:36 -070090 show_regs(regs);
Paul Mundt6b002232006-10-12 17:07:45 +090091
92 printk("Process: %s (pid: %d, stack limit = %p)\n",
93 current->comm, current->pid, task_stack_page(current) + 1);
94
95 if (!user_mode(regs) || in_interrupt())
96 dump_mem("Stack: ", regs->regs[15], THREAD_SIZE +
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +090097 (unsigned long)task_stack_page(current));
Paul Mundt6b002232006-10-12 17:07:45 +090098
99 bust_spinlocks(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100 spin_unlock_irq(&die_lock);
101 do_exit(SIGSEGV);
102}
103
Paul Mundt6b002232006-10-12 17:07:45 +0900104static inline void die_if_kernel(const char *str, struct pt_regs *regs,
105 long err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106{
107 if (!user_mode(regs))
108 die(str, regs, err);
109}
110
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111/*
112 * try and fix up kernelspace address errors
113 * - userspace errors just cause EFAULT to be returned, resulting in SEGV
114 * - kernel/userspace interfaces cause a jump to an appropriate handler
115 * - other kernel errors are bad
116 * - return 0 if fixed-up, -EFAULT if non-fatal (to the kernel) fault
117 */
118static int die_if_no_fixup(const char * str, struct pt_regs * regs, long err)
119{
Paul Mundt6b002232006-10-12 17:07:45 +0900120 if (!user_mode(regs)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 const struct exception_table_entry *fixup;
122 fixup = search_exception_tables(regs->pc);
123 if (fixup) {
124 regs->pc = fixup->fixup;
125 return 0;
126 }
127 die(str, regs, err);
128 }
129 return -EFAULT;
130}
131
132/*
133 * handle an instruction that does an unaligned memory access by emulating the
134 * desired behaviour
135 * - note that PC _may not_ point to the faulting instruction
136 * (if that instruction is in a branch delay slot)
137 * - return 0 if emulation okay, -EFAULT on existential error
138 */
139static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs)
140{
141 int ret, index, count;
142 unsigned long *rm, *rn;
143 unsigned char *src, *dst;
144
145 index = (instruction>>8)&15; /* 0x0F00 */
146 rn = &regs->regs[index];
147
148 index = (instruction>>4)&15; /* 0x00F0 */
149 rm = &regs->regs[index];
150
151 count = 1<<(instruction&3);
152
153 ret = -EFAULT;
154 switch (instruction>>12) {
155 case 0: /* mov.[bwl] to/from memory via r0+rn */
156 if (instruction & 8) {
157 /* from memory */
158 src = (unsigned char*) *rm;
159 src += regs->regs[0];
160 dst = (unsigned char*) rn;
161 *(unsigned long*)dst = 0;
162
163#ifdef __LITTLE_ENDIAN__
164 if (copy_from_user(dst, src, count))
165 goto fetch_fault;
166
167 if ((count == 2) && dst[1] & 0x80) {
168 dst[2] = 0xff;
169 dst[3] = 0xff;
170 }
171#else
172 dst += 4-count;
173
174 if (__copy_user(dst, src, count))
175 goto fetch_fault;
176
177 if ((count == 2) && dst[2] & 0x80) {
178 dst[0] = 0xff;
179 dst[1] = 0xff;
180 }
181#endif
182 } else {
183 /* to memory */
184 src = (unsigned char*) rm;
185#if !defined(__LITTLE_ENDIAN__)
186 src += 4-count;
187#endif
188 dst = (unsigned char*) *rn;
189 dst += regs->regs[0];
190
191 if (copy_to_user(dst, src, count))
192 goto fetch_fault;
193 }
194 ret = 0;
195 break;
196
197 case 1: /* mov.l Rm,@(disp,Rn) */
198 src = (unsigned char*) rm;
199 dst = (unsigned char*) *rn;
200 dst += (instruction&0x000F)<<2;
201
202 if (copy_to_user(dst,src,4))
203 goto fetch_fault;
204 ret = 0;
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900205 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206
207 case 2: /* mov.[bwl] to memory, possibly with pre-decrement */
208 if (instruction & 4)
209 *rn -= count;
210 src = (unsigned char*) rm;
211 dst = (unsigned char*) *rn;
212#if !defined(__LITTLE_ENDIAN__)
213 src += 4-count;
214#endif
215 if (copy_to_user(dst, src, count))
216 goto fetch_fault;
217 ret = 0;
218 break;
219
220 case 5: /* mov.l @(disp,Rm),Rn */
221 src = (unsigned char*) *rm;
222 src += (instruction&0x000F)<<2;
223 dst = (unsigned char*) rn;
224 *(unsigned long*)dst = 0;
225
226 if (copy_from_user(dst,src,4))
227 goto fetch_fault;
228 ret = 0;
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900229 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230
231 case 6: /* mov.[bwl] from memory, possibly with post-increment */
232 src = (unsigned char*) *rm;
233 if (instruction & 4)
234 *rm += count;
235 dst = (unsigned char*) rn;
236 *(unsigned long*)dst = 0;
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900237
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238#ifdef __LITTLE_ENDIAN__
239 if (copy_from_user(dst, src, count))
240 goto fetch_fault;
241
242 if ((count == 2) && dst[1] & 0x80) {
243 dst[2] = 0xff;
244 dst[3] = 0xff;
245 }
246#else
247 dst += 4-count;
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900248
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 if (copy_from_user(dst, src, count))
250 goto fetch_fault;
251
252 if ((count == 2) && dst[2] & 0x80) {
253 dst[0] = 0xff;
254 dst[1] = 0xff;
255 }
256#endif
257 ret = 0;
258 break;
259
260 case 8:
261 switch ((instruction&0xFF00)>>8) {
262 case 0x81: /* mov.w R0,@(disp,Rn) */
263 src = (unsigned char*) &regs->regs[0];
264#if !defined(__LITTLE_ENDIAN__)
265 src += 2;
266#endif
267 dst = (unsigned char*) *rm; /* called Rn in the spec */
268 dst += (instruction&0x000F)<<1;
269
270 if (copy_to_user(dst, src, 2))
271 goto fetch_fault;
272 ret = 0;
273 break;
274
275 case 0x85: /* mov.w @(disp,Rm),R0 */
276 src = (unsigned char*) *rm;
277 src += (instruction&0x000F)<<1;
278 dst = (unsigned char*) &regs->regs[0];
279 *(unsigned long*)dst = 0;
280
281#if !defined(__LITTLE_ENDIAN__)
282 dst += 2;
283#endif
284
285 if (copy_from_user(dst, src, 2))
286 goto fetch_fault;
287
288#ifdef __LITTLE_ENDIAN__
289 if (dst[1] & 0x80) {
290 dst[2] = 0xff;
291 dst[3] = 0xff;
292 }
293#else
294 if (dst[2] & 0x80) {
295 dst[0] = 0xff;
296 dst[1] = 0xff;
297 }
298#endif
299 ret = 0;
300 break;
301 }
302 break;
303 }
304 return ret;
305
306 fetch_fault:
307 /* Argh. Address not only misaligned but also non-existent.
308 * Raise an EFAULT and see if it's trapped
309 */
310 return die_if_no_fixup("Fault in unaligned fixup", regs, 0);
311}
312
313/*
314 * emulate the instruction in the delay slot
315 * - fetches the instruction from PC+2
316 */
317static inline int handle_unaligned_delayslot(struct pt_regs *regs)
318{
319 u16 instruction;
320
321 if (copy_from_user(&instruction, (u16 *)(regs->pc+2), 2)) {
322 /* the instruction-fetch faulted */
323 if (user_mode(regs))
324 return -EFAULT;
325
326 /* kernel */
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900327 die("delay-slot-insn faulting in handle_unaligned_delayslot",
328 regs, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 }
330
331 return handle_unaligned_ins(instruction,regs);
332}
333
334/*
335 * handle an instruction that does an unaligned memory access
336 * - have to be careful of branch delay-slot instructions that fault
337 * SH3:
338 * - if the branch would be taken PC points to the branch
339 * - if the branch would not be taken, PC points to delay-slot
340 * SH4:
341 * - PC always points to delayed branch
342 * - return 0 if handled, -EFAULT if failed (may not return if in kernel)
343 */
344
345/* Macros to determine offset from current PC for branch instructions */
346/* Explicit type coercion is used to force sign extension where needed */
347#define SH_PC_8BIT_OFFSET(instr) ((((signed char)(instr))*2) + 4)
348#define SH_PC_12BIT_OFFSET(instr) ((((signed short)(instr<<4))>>3) + 4)
349
Paul Mundt710ee0c2006-11-05 16:48:42 +0900350/*
351 * XXX: SH-2A needs this too, but it needs an overhaul thanks to mixed 32-bit
352 * opcodes..
353 */
354#ifndef CONFIG_CPU_SH2A
355static int handle_unaligned_notify_count = 10;
356
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
358{
359 u_int rm;
360 int ret, index;
361
362 index = (instruction>>8)&15; /* 0x0F00 */
363 rm = regs->regs[index];
364
365 /* shout about the first ten userspace fixups */
366 if (user_mode(regs) && handle_unaligned_notify_count>0) {
367 handle_unaligned_notify_count--;
368
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900369 printk(KERN_NOTICE "Fixing up unaligned userspace access "
370 "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 current->comm,current->pid,(u16*)regs->pc,instruction);
372 }
373
374 ret = -EFAULT;
375 switch (instruction&0xF000) {
376 case 0x0000:
377 if (instruction==0x000B) {
378 /* rts */
379 ret = handle_unaligned_delayslot(regs);
380 if (ret==0)
381 regs->pc = regs->pr;
382 }
383 else if ((instruction&0x00FF)==0x0023) {
384 /* braf @Rm */
385 ret = handle_unaligned_delayslot(regs);
386 if (ret==0)
387 regs->pc += rm + 4;
388 }
389 else if ((instruction&0x00FF)==0x0003) {
390 /* bsrf @Rm */
391 ret = handle_unaligned_delayslot(regs);
392 if (ret==0) {
393 regs->pr = regs->pc + 4;
394 regs->pc += rm + 4;
395 }
396 }
397 else {
398 /* mov.[bwl] to/from memory via r0+rn */
399 goto simple;
400 }
401 break;
402
403 case 0x1000: /* mov.l Rm,@(disp,Rn) */
404 goto simple;
405
406 case 0x2000: /* mov.[bwl] to memory, possibly with pre-decrement */
407 goto simple;
408
409 case 0x4000:
410 if ((instruction&0x00FF)==0x002B) {
411 /* jmp @Rm */
412 ret = handle_unaligned_delayslot(regs);
413 if (ret==0)
414 regs->pc = rm;
415 }
416 else if ((instruction&0x00FF)==0x000B) {
417 /* jsr @Rm */
418 ret = handle_unaligned_delayslot(regs);
419 if (ret==0) {
420 regs->pr = regs->pc + 4;
421 regs->pc = rm;
422 }
423 }
424 else {
425 /* mov.[bwl] to/from memory via r0+rn */
426 goto simple;
427 }
428 break;
429
430 case 0x5000: /* mov.l @(disp,Rm),Rn */
431 goto simple;
432
433 case 0x6000: /* mov.[bwl] from memory, possibly with post-increment */
434 goto simple;
435
436 case 0x8000: /* bf lab, bf/s lab, bt lab, bt/s lab */
437 switch (instruction&0x0F00) {
438 case 0x0100: /* mov.w R0,@(disp,Rm) */
439 goto simple;
440 case 0x0500: /* mov.w @(disp,Rm),R0 */
441 goto simple;
442 case 0x0B00: /* bf lab - no delayslot*/
443 break;
444 case 0x0F00: /* bf/s lab */
445 ret = handle_unaligned_delayslot(regs);
446 if (ret==0) {
447#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)
448 if ((regs->sr & 0x00000001) != 0)
449 regs->pc += 4; /* next after slot */
450 else
451#endif
452 regs->pc += SH_PC_8BIT_OFFSET(instruction);
453 }
454 break;
455 case 0x0900: /* bt lab - no delayslot */
456 break;
457 case 0x0D00: /* bt/s lab */
458 ret = handle_unaligned_delayslot(regs);
459 if (ret==0) {
460#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)
461 if ((regs->sr & 0x00000001) == 0)
462 regs->pc += 4; /* next after slot */
463 else
464#endif
465 regs->pc += SH_PC_8BIT_OFFSET(instruction);
466 }
467 break;
468 }
469 break;
470
471 case 0xA000: /* bra label */
472 ret = handle_unaligned_delayslot(regs);
473 if (ret==0)
474 regs->pc += SH_PC_12BIT_OFFSET(instruction);
475 break;
476
477 case 0xB000: /* bsr label */
478 ret = handle_unaligned_delayslot(regs);
479 if (ret==0) {
480 regs->pr = regs->pc + 4;
481 regs->pc += SH_PC_12BIT_OFFSET(instruction);
482 }
483 break;
484 }
485 return ret;
486
487 /* handle non-delay-slot instruction */
488 simple:
489 ret = handle_unaligned_ins(instruction,regs);
490 if (ret==0)
491 regs->pc += 2;
492 return ret;
493}
Paul Mundt710ee0c2006-11-05 16:48:42 +0900494#endif /* CONFIG_CPU_SH2A */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495
Yoshinori Sato0983b312006-11-05 15:58:47 +0900496#ifdef CONFIG_CPU_HAS_SR_RB
497#define lookup_exception_vector(x) \
498 __asm__ __volatile__ ("stc r2_bank, %0\n\t" : "=r" ((x)))
499#else
500#define lookup_exception_vector(x) \
501 __asm__ __volatile__ ("mov r4, %0\n\t" : "=r" ((x)))
502#endif
503
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504/*
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900505 * Handle various address error exceptions:
506 * - instruction address error:
507 * misaligned PC
508 * PC >= 0x80000000 in user mode
509 * - data address error (read and write)
510 * misaligned data access
511 * access to >= 0x80000000 is user mode
512 * Unfortuntaly we can't distinguish between instruction address error
513 * and data address errors caused by read acceses.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 */
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900515asmlinkage void do_address_error(struct pt_regs *regs,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 unsigned long writeaccess,
517 unsigned long address)
518{
Yoshinori Sato0983b312006-11-05 15:58:47 +0900519 unsigned long error_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 mm_segment_t oldfs;
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900521 siginfo_t info;
Paul Mundt710ee0c2006-11-05 16:48:42 +0900522#ifndef CONFIG_CPU_SH2A
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 u16 instruction;
524 int tmp;
Paul Mundt710ee0c2006-11-05 16:48:42 +0900525#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526
Yoshinori Sato0983b312006-11-05 15:58:47 +0900527 /* Intentional ifdef */
528#ifdef CONFIG_CPU_HAS_SR_RB
529 lookup_exception_vector(error_code);
530#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531
532 oldfs = get_fs();
533
534 if (user_mode(regs)) {
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900535 int si_code = BUS_ADRERR;
536
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 local_irq_enable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538
539 /* bad PC is not something we can fix */
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900540 if (regs->pc & 1) {
541 si_code = BUS_ADRALN;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 goto uspace_segv;
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900543 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544
Yoshinori Sato0983b312006-11-05 15:58:47 +0900545#ifndef CONFIG_CPU_SH2A
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 set_fs(USER_DS);
547 if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) {
548 /* Argh. Fault on the instruction itself.
549 This should never happen non-SMP
550 */
551 set_fs(oldfs);
552 goto uspace_segv;
553 }
554
555 tmp = handle_unaligned_access(instruction, regs);
556 set_fs(oldfs);
557
558 if (tmp==0)
559 return; /* sorted */
Yoshinori Sato0983b312006-11-05 15:58:47 +0900560#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900562uspace_segv:
563 printk(KERN_NOTICE "Sending SIGBUS to \"%s\" due to unaligned "
564 "access (PC %lx PR %lx)\n", current->comm, regs->pc,
565 regs->pr);
566
567 info.si_signo = SIGBUS;
568 info.si_errno = 0;
569 info.si_code = si_code;
570 info.si_addr = (void *) address;
571 force_sig_info(SIGBUS, &info, current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 } else {
573 if (regs->pc & 1)
574 die("unaligned program counter", regs, error_code);
575
Yoshinori Sato0983b312006-11-05 15:58:47 +0900576#ifndef CONFIG_CPU_SH2A
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 set_fs(KERNEL_DS);
578 if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) {
579 /* Argh. Fault on the instruction itself.
580 This should never happen non-SMP
581 */
582 set_fs(oldfs);
583 die("insn faulting in do_address_error", regs, 0);
584 }
585
586 handle_unaligned_access(instruction, regs);
587 set_fs(oldfs);
Yoshinori Sato0983b312006-11-05 15:58:47 +0900588#else
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900589 printk(KERN_NOTICE "Killing process \"%s\" due to unaligned "
590 "access\n", current->comm);
591
Yoshinori Sato0983b312006-11-05 15:58:47 +0900592 force_sig(SIGSEGV, current);
593#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 }
595}
596
597#ifdef CONFIG_SH_DSP
598/*
599 * SH-DSP support gerg@snapgear.com.
600 */
601int is_dsp_inst(struct pt_regs *regs)
602{
603 unsigned short inst;
604
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900605 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 * Safe guard if DSP mode is already enabled or we're lacking
607 * the DSP altogether.
608 */
609 if (!(cpu_data->flags & CPU_HAS_DSP) || (regs->sr & SR_DSP))
610 return 0;
611
612 get_user(inst, ((unsigned short *) regs->pc));
613
614 inst &= 0xf000;
615
616 /* Check for any type of DSP or support instruction */
617 if ((inst == 0xf000) || (inst == 0x4000))
618 return 1;
619
620 return 0;
621}
622#else
623#define is_dsp_inst(regs) (0)
624#endif /* CONFIG_SH_DSP */
625
Yoshinori Sato0983b312006-11-05 15:58:47 +0900626#ifdef CONFIG_CPU_SH2A
627asmlinkage void do_divide_error(unsigned long r4, unsigned long r5,
628 unsigned long r6, unsigned long r7,
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900629 struct pt_regs __regs)
Yoshinori Sato0983b312006-11-05 15:58:47 +0900630{
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900631 struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
Yoshinori Sato0983b312006-11-05 15:58:47 +0900632 siginfo_t info;
633
Yoshinori Sato0983b312006-11-05 15:58:47 +0900634 switch (r4) {
635 case TRAP_DIVZERO_ERROR:
636 info.si_code = FPE_INTDIV;
637 break;
638 case TRAP_DIVOVF_ERROR:
639 info.si_code = FPE_INTOVF;
640 break;
641 }
642
643 force_sig_info(SIGFPE, &info, current);
644}
645#endif
646
Paul Mundt1f666582006-10-19 16:20:25 +0900647/* arch/sh/kernel/cpu/sh4/fpu.c */
648extern int do_fpu_inst(unsigned short, struct pt_regs *);
649extern asmlinkage void do_fpu_state_restore(unsigned long r4, unsigned long r5,
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900650 unsigned long r6, unsigned long r7, struct pt_regs __regs);
Takashi YOSHII4b565682006-09-27 17:15:32 +0900651
652asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5,
653 unsigned long r6, unsigned long r7,
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900654 struct pt_regs __regs)
Takashi YOSHII4b565682006-09-27 17:15:32 +0900655{
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900656 struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
Takashi YOSHII4b565682006-09-27 17:15:32 +0900657 unsigned long error_code;
658 struct task_struct *tsk = current;
659
660#ifdef CONFIG_SH_FPU_EMU
Yoshinori Sato0983b312006-11-05 15:58:47 +0900661 unsigned short inst = 0;
Takashi YOSHII4b565682006-09-27 17:15:32 +0900662 int err;
663
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900664 get_user(inst, (unsigned short*)regs->pc);
Takashi YOSHII4b565682006-09-27 17:15:32 +0900665
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900666 err = do_fpu_inst(inst, regs);
Takashi YOSHII4b565682006-09-27 17:15:32 +0900667 if (!err) {
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900668 regs->pc += 2;
Takashi YOSHII4b565682006-09-27 17:15:32 +0900669 return;
670 }
671 /* not a FPU inst. */
672#endif
673
674#ifdef CONFIG_SH_DSP
675 /* Check if it's a DSP instruction */
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900676 if (is_dsp_inst(regs)) {
Takashi YOSHII4b565682006-09-27 17:15:32 +0900677 /* Enable DSP mode, and restart instruction. */
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900678 regs->sr |= SR_DSP;
Takashi YOSHII4b565682006-09-27 17:15:32 +0900679 return;
680 }
681#endif
682
Yoshinori Sato0983b312006-11-05 15:58:47 +0900683 lookup_exception_vector(error_code);
684
Takashi YOSHII4b565682006-09-27 17:15:32 +0900685 local_irq_enable();
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900686 CHK_REMOTE_DEBUG(regs);
Takashi YOSHII4b565682006-09-27 17:15:32 +0900687 force_sig(SIGILL, tsk);
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900688 die_if_no_fixup("reserved instruction", regs, error_code);
Takashi YOSHII4b565682006-09-27 17:15:32 +0900689}
690
691#ifdef CONFIG_SH_FPU_EMU
692static int emulate_branch(unsigned short inst, struct pt_regs* regs)
693{
694 /*
695 * bfs: 8fxx: PC+=d*2+4;
696 * bts: 8dxx: PC+=d*2+4;
697 * bra: axxx: PC+=D*2+4;
698 * bsr: bxxx: PC+=D*2+4 after PR=PC+4;
699 * braf:0x23: PC+=Rn*2+4;
700 * bsrf:0x03: PC+=Rn*2+4 after PR=PC+4;
701 * jmp: 4x2b: PC=Rn;
702 * jsr: 4x0b: PC=Rn after PR=PC+4;
703 * rts: 000b: PC=PR;
704 */
705 if ((inst & 0xfd00) == 0x8d00) {
706 regs->pc += SH_PC_8BIT_OFFSET(inst);
707 return 0;
708 }
709
710 if ((inst & 0xe000) == 0xa000) {
711 regs->pc += SH_PC_12BIT_OFFSET(inst);
712 return 0;
713 }
714
715 if ((inst & 0xf0df) == 0x0003) {
716 regs->pc += regs->regs[(inst & 0x0f00) >> 8] + 4;
717 return 0;
718 }
719
720 if ((inst & 0xf0df) == 0x400b) {
721 regs->pc = regs->regs[(inst & 0x0f00) >> 8];
722 return 0;
723 }
724
725 if ((inst & 0xffff) == 0x000b) {
726 regs->pc = regs->pr;
727 return 0;
728 }
729
730 return 1;
731}
732#endif
733
734asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5,
735 unsigned long r6, unsigned long r7,
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900736 struct pt_regs __regs)
Takashi YOSHII4b565682006-09-27 17:15:32 +0900737{
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900738 struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
Takashi YOSHII4b565682006-09-27 17:15:32 +0900739 unsigned long error_code;
740 struct task_struct *tsk = current;
741#ifdef CONFIG_SH_FPU_EMU
Yoshinori Sato0983b312006-11-05 15:58:47 +0900742 unsigned short inst = 0;
Takashi YOSHII4b565682006-09-27 17:15:32 +0900743
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900744 get_user(inst, (unsigned short *)regs->pc + 1);
745 if (!do_fpu_inst(inst, regs)) {
746 get_user(inst, (unsigned short *)regs->pc);
747 if (!emulate_branch(inst, regs))
Takashi YOSHII4b565682006-09-27 17:15:32 +0900748 return;
749 /* fault in branch.*/
750 }
751 /* not a FPU inst. */
752#endif
753
Yoshinori Sato0983b312006-11-05 15:58:47 +0900754 lookup_exception_vector(error_code);
755
Takashi YOSHII4b565682006-09-27 17:15:32 +0900756 local_irq_enable();
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900757 CHK_REMOTE_DEBUG(regs);
Takashi YOSHII4b565682006-09-27 17:15:32 +0900758 force_sig(SIGILL, tsk);
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900759 die_if_no_fixup("illegal slot instruction", regs, error_code);
Takashi YOSHII4b565682006-09-27 17:15:32 +0900760}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761
762asmlinkage void do_exception_error(unsigned long r4, unsigned long r5,
763 unsigned long r6, unsigned long r7,
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900764 struct pt_regs __regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765{
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900766 struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 long ex;
Yoshinori Sato0983b312006-11-05 15:58:47 +0900768
769 lookup_exception_vector(ex);
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900770 die_if_kernel("exception", regs, ex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771}
772
773#if defined(CONFIG_SH_STANDARD_BIOS)
774void *gdb_vbr_vector;
775
776static inline void __init gdb_vbr_init(void)
777{
778 register unsigned long vbr;
779
780 /*
781 * Read the old value of the VBR register to initialise
782 * the vector through which debug and BIOS traps are
783 * delegated by the Linux trap handler.
784 */
785 asm volatile("stc vbr, %0" : "=r" (vbr));
786
787 gdb_vbr_vector = (void *)(vbr + 0x100);
788 printk("Setting GDB trap vector to 0x%08lx\n",
789 (unsigned long)gdb_vbr_vector);
790}
791#endif
792
793void __init per_cpu_trap_init(void)
794{
795 extern void *vbr_base;
796
797#ifdef CONFIG_SH_STANDARD_BIOS
798 gdb_vbr_init();
799#endif
800
801 /* NOTE: The VBR value should be at P1
802 (or P2, virtural "fixed" address space).
803 It's definitely should not in physical address. */
804
805 asm volatile("ldc %0, vbr"
806 : /* no output */
807 : "r" (&vbr_base)
808 : "memory");
809}
810
Paul Mundt1f666582006-10-19 16:20:25 +0900811void *set_exception_table_vec(unsigned int vec, void *handler)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812{
813 extern void *exception_handling_table[];
Paul Mundt1f666582006-10-19 16:20:25 +0900814 void *old_handler;
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900815
Paul Mundt1f666582006-10-19 16:20:25 +0900816 old_handler = exception_handling_table[vec];
817 exception_handling_table[vec] = handler;
818 return old_handler;
819}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820
Yoshinori Sato0983b312006-11-05 15:58:47 +0900821extern asmlinkage void address_error_handler(unsigned long r4, unsigned long r5,
822 unsigned long r6, unsigned long r7,
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900823 struct pt_regs __regs);
Yoshinori Sato0983b312006-11-05 15:58:47 +0900824
Paul Mundt1f666582006-10-19 16:20:25 +0900825void __init trap_init(void)
826{
827 set_exception_table_vec(TRAP_RESERVED_INST, do_reserved_inst);
828 set_exception_table_vec(TRAP_ILLEGAL_SLOT_INST, do_illegal_slot_inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829
Takashi YOSHII4b565682006-09-27 17:15:32 +0900830#if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SH_FPU) || \
831 defined(CONFIG_SH_FPU_EMU)
832 /*
833 * For SH-4 lacking an FPU, treat floating point instructions as
834 * reserved. They'll be handled in the math-emu case, or faulted on
835 * otherwise.
836 */
Paul Mundt1f666582006-10-19 16:20:25 +0900837 set_exception_table_evt(0x800, do_reserved_inst);
838 set_exception_table_evt(0x820, do_illegal_slot_inst);
839#elif defined(CONFIG_SH_FPU)
840 set_exception_table_evt(0x800, do_fpu_state_restore);
841 set_exception_table_evt(0x820, do_fpu_state_restore);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842#endif
Yoshinori Sato0983b312006-11-05 15:58:47 +0900843
844#ifdef CONFIG_CPU_SH2
845 set_exception_table_vec(TRAP_ADDRESS_ERROR, address_error_handler);
846#endif
847#ifdef CONFIG_CPU_SH2A
848 set_exception_table_vec(TRAP_DIVZERO_ERROR, do_divide_error);
849 set_exception_table_vec(TRAP_DIVOVF_ERROR, do_divide_error);
850#endif
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900851
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 /* Setup VBR for boot cpu */
853 per_cpu_trap_init();
854}
855
Paul Mundt6b002232006-10-12 17:07:45 +0900856void show_trace(struct task_struct *tsk, unsigned long *sp,
857 struct pt_regs *regs)
858{
859 unsigned long addr;
860
861 if (regs && user_mode(regs))
862 return;
863
864 printk("\nCall trace: ");
865#ifdef CONFIG_KALLSYMS
866 printk("\n");
867#endif
868
869 while (!kstack_end(sp)) {
870 addr = *sp++;
871 if (kernel_text_address(addr))
872 print_ip_sym(addr);
873 }
874
875 printk("\n");
Paul Mundt9b8c90e2006-12-06 11:07:51 +0900876
877 if (!tsk)
878 tsk = current;
879
880 debug_show_held_locks(tsk);
Paul Mundt6b002232006-10-12 17:07:45 +0900881}
882
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883void show_stack(struct task_struct *tsk, unsigned long *sp)
884{
Paul Mundt6b002232006-10-12 17:07:45 +0900885 unsigned long stack;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886
Paul Mundta6a311392006-09-27 18:22:14 +0900887 if (!tsk)
888 tsk = current;
889 if (tsk == current)
890 sp = (unsigned long *)current_stack_pointer;
891 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 sp = (unsigned long *)tsk->thread.sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893
Paul Mundt6b002232006-10-12 17:07:45 +0900894 stack = (unsigned long)sp;
895 dump_mem("Stack: ", stack, THREAD_SIZE +
896 (unsigned long)task_stack_page(tsk));
897 show_trace(tsk, sp, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898}
899
900void dump_stack(void)
901{
902 show_stack(NULL, NULL);
903}
904EXPORT_SYMBOL(dump_stack);