blob: 0ee298079d827134c1f6ad9aaa7ae8e7ffee2173 [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <asm/system.h>
22#include <asm/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070023
24#ifdef CONFIG_SH_KGDB
25#include <asm/kgdb.h>
Stuart Menefyf0bc8142006-11-21 11:16:57 +090026#define CHK_REMOTE_DEBUG(regs) \
27{ \
Takashi YOSHII4b565682006-09-27 17:15:32 +090028 if (kgdb_debug_hook && !user_mode(regs))\
29 (*kgdb_debug_hook)(regs); \
Linus Torvalds1da177e2005-04-16 15:20:36 -070030}
31#else
32#define CHK_REMOTE_DEBUG(regs)
33#endif
34
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#ifdef CONFIG_CPU_SH2
Yoshinori Sato0983b312006-11-05 15:58:47 +090036# define TRAP_RESERVED_INST 4
37# define TRAP_ILLEGAL_SLOT_INST 6
38# define TRAP_ADDRESS_ERROR 9
39# ifdef CONFIG_CPU_SH2A
40# define TRAP_DIVZERO_ERROR 17
41# define TRAP_DIVOVF_ERROR 18
42# endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#else
44#define TRAP_RESERVED_INST 12
45#define TRAP_ILLEGAL_SLOT_INST 13
46#endif
47
Paul Mundt6b002232006-10-12 17:07:45 +090048static void dump_mem(const char *str, unsigned long bottom, unsigned long top)
49{
50 unsigned long p;
51 int i;
52
53 printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top);
54
55 for (p = bottom & ~31; p < top; ) {
56 printk("%04lx: ", p & 0xffff);
57
58 for (i = 0; i < 8; i++, p += 4) {
59 unsigned int val;
60
61 if (p < bottom || p >= top)
62 printk(" ");
63 else {
64 if (__get_user(val, (unsigned int __user *)p)) {
65 printk("\n");
66 return;
67 }
68 printk("%08x ", val);
69 }
70 }
71 printk("\n");
72 }
73}
Linus Torvalds1da177e2005-04-16 15:20:36 -070074
Paul Mundt765ae312006-09-27 11:31:32 +090075DEFINE_SPINLOCK(die_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070076
77void die(const char * str, struct pt_regs * regs, long err)
78{
79 static int die_counter;
80
81 console_verbose();
82 spin_lock_irq(&die_lock);
Paul Mundt6b002232006-10-12 17:07:45 +090083 bust_spinlocks(1);
84
Linus Torvalds1da177e2005-04-16 15:20:36 -070085 printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
Paul Mundt6b002232006-10-12 17:07:45 +090086
Linus Torvalds1da177e2005-04-16 15:20:36 -070087 CHK_REMOTE_DEBUG(regs);
Paul Mundt6b002232006-10-12 17:07:45 +090088 print_modules();
Linus Torvalds1da177e2005-04-16 15:20:36 -070089 show_regs(regs);
Paul Mundt6b002232006-10-12 17:07:45 +090090
91 printk("Process: %s (pid: %d, stack limit = %p)\n",
92 current->comm, current->pid, task_stack_page(current) + 1);
93
94 if (!user_mode(regs) || in_interrupt())
95 dump_mem("Stack: ", regs->regs[15], THREAD_SIZE +
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +090096 (unsigned long)task_stack_page(current));
Paul Mundt6b002232006-10-12 17:07:45 +090097
98 bust_spinlocks(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 spin_unlock_irq(&die_lock);
100 do_exit(SIGSEGV);
101}
102
Paul Mundt6b002232006-10-12 17:07:45 +0900103static inline void die_if_kernel(const char *str, struct pt_regs *regs,
104 long err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105{
106 if (!user_mode(regs))
107 die(str, regs, err);
108}
109
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110/*
111 * try and fix up kernelspace address errors
112 * - userspace errors just cause EFAULT to be returned, resulting in SEGV
113 * - kernel/userspace interfaces cause a jump to an appropriate handler
114 * - other kernel errors are bad
115 * - return 0 if fixed-up, -EFAULT if non-fatal (to the kernel) fault
116 */
117static int die_if_no_fixup(const char * str, struct pt_regs * regs, long err)
118{
Paul Mundt6b002232006-10-12 17:07:45 +0900119 if (!user_mode(regs)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120 const struct exception_table_entry *fixup;
121 fixup = search_exception_tables(regs->pc);
122 if (fixup) {
123 regs->pc = fixup->fixup;
124 return 0;
125 }
126 die(str, regs, err);
127 }
128 return -EFAULT;
129}
130
131/*
132 * handle an instruction that does an unaligned memory access by emulating the
133 * desired behaviour
134 * - note that PC _may not_ point to the faulting instruction
135 * (if that instruction is in a branch delay slot)
136 * - return 0 if emulation okay, -EFAULT on existential error
137 */
138static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs)
139{
140 int ret, index, count;
141 unsigned long *rm, *rn;
142 unsigned char *src, *dst;
143
144 index = (instruction>>8)&15; /* 0x0F00 */
145 rn = &regs->regs[index];
146
147 index = (instruction>>4)&15; /* 0x00F0 */
148 rm = &regs->regs[index];
149
150 count = 1<<(instruction&3);
151
152 ret = -EFAULT;
153 switch (instruction>>12) {
154 case 0: /* mov.[bwl] to/from memory via r0+rn */
155 if (instruction & 8) {
156 /* from memory */
157 src = (unsigned char*) *rm;
158 src += regs->regs[0];
159 dst = (unsigned char*) rn;
160 *(unsigned long*)dst = 0;
161
162#ifdef __LITTLE_ENDIAN__
163 if (copy_from_user(dst, src, count))
164 goto fetch_fault;
165
166 if ((count == 2) && dst[1] & 0x80) {
167 dst[2] = 0xff;
168 dst[3] = 0xff;
169 }
170#else
171 dst += 4-count;
172
173 if (__copy_user(dst, src, count))
174 goto fetch_fault;
175
176 if ((count == 2) && dst[2] & 0x80) {
177 dst[0] = 0xff;
178 dst[1] = 0xff;
179 }
180#endif
181 } else {
182 /* to memory */
183 src = (unsigned char*) rm;
184#if !defined(__LITTLE_ENDIAN__)
185 src += 4-count;
186#endif
187 dst = (unsigned char*) *rn;
188 dst += regs->regs[0];
189
190 if (copy_to_user(dst, src, count))
191 goto fetch_fault;
192 }
193 ret = 0;
194 break;
195
196 case 1: /* mov.l Rm,@(disp,Rn) */
197 src = (unsigned char*) rm;
198 dst = (unsigned char*) *rn;
199 dst += (instruction&0x000F)<<2;
200
201 if (copy_to_user(dst,src,4))
202 goto fetch_fault;
203 ret = 0;
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900204 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
206 case 2: /* mov.[bwl] to memory, possibly with pre-decrement */
207 if (instruction & 4)
208 *rn -= count;
209 src = (unsigned char*) rm;
210 dst = (unsigned char*) *rn;
211#if !defined(__LITTLE_ENDIAN__)
212 src += 4-count;
213#endif
214 if (copy_to_user(dst, src, count))
215 goto fetch_fault;
216 ret = 0;
217 break;
218
219 case 5: /* mov.l @(disp,Rm),Rn */
220 src = (unsigned char*) *rm;
221 src += (instruction&0x000F)<<2;
222 dst = (unsigned char*) rn;
223 *(unsigned long*)dst = 0;
224
225 if (copy_from_user(dst,src,4))
226 goto fetch_fault;
227 ret = 0;
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900228 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229
230 case 6: /* mov.[bwl] from memory, possibly with post-increment */
231 src = (unsigned char*) *rm;
232 if (instruction & 4)
233 *rm += count;
234 dst = (unsigned char*) rn;
235 *(unsigned long*)dst = 0;
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900236
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237#ifdef __LITTLE_ENDIAN__
238 if (copy_from_user(dst, src, count))
239 goto fetch_fault;
240
241 if ((count == 2) && dst[1] & 0x80) {
242 dst[2] = 0xff;
243 dst[3] = 0xff;
244 }
245#else
246 dst += 4-count;
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900247
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 if (copy_from_user(dst, src, count))
249 goto fetch_fault;
250
251 if ((count == 2) && dst[2] & 0x80) {
252 dst[0] = 0xff;
253 dst[1] = 0xff;
254 }
255#endif
256 ret = 0;
257 break;
258
259 case 8:
260 switch ((instruction&0xFF00)>>8) {
261 case 0x81: /* mov.w R0,@(disp,Rn) */
262 src = (unsigned char*) &regs->regs[0];
263#if !defined(__LITTLE_ENDIAN__)
264 src += 2;
265#endif
266 dst = (unsigned char*) *rm; /* called Rn in the spec */
267 dst += (instruction&0x000F)<<1;
268
269 if (copy_to_user(dst, src, 2))
270 goto fetch_fault;
271 ret = 0;
272 break;
273
274 case 0x85: /* mov.w @(disp,Rm),R0 */
275 src = (unsigned char*) *rm;
276 src += (instruction&0x000F)<<1;
277 dst = (unsigned char*) &regs->regs[0];
278 *(unsigned long*)dst = 0;
279
280#if !defined(__LITTLE_ENDIAN__)
281 dst += 2;
282#endif
283
284 if (copy_from_user(dst, src, 2))
285 goto fetch_fault;
286
287#ifdef __LITTLE_ENDIAN__
288 if (dst[1] & 0x80) {
289 dst[2] = 0xff;
290 dst[3] = 0xff;
291 }
292#else
293 if (dst[2] & 0x80) {
294 dst[0] = 0xff;
295 dst[1] = 0xff;
296 }
297#endif
298 ret = 0;
299 break;
300 }
301 break;
302 }
303 return ret;
304
305 fetch_fault:
306 /* Argh. Address not only misaligned but also non-existent.
307 * Raise an EFAULT and see if it's trapped
308 */
309 return die_if_no_fixup("Fault in unaligned fixup", regs, 0);
310}
311
312/*
313 * emulate the instruction in the delay slot
314 * - fetches the instruction from PC+2
315 */
316static inline int handle_unaligned_delayslot(struct pt_regs *regs)
317{
318 u16 instruction;
319
320 if (copy_from_user(&instruction, (u16 *)(regs->pc+2), 2)) {
321 /* the instruction-fetch faulted */
322 if (user_mode(regs))
323 return -EFAULT;
324
325 /* kernel */
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900326 die("delay-slot-insn faulting in handle_unaligned_delayslot",
327 regs, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 }
329
330 return handle_unaligned_ins(instruction,regs);
331}
332
333/*
334 * handle an instruction that does an unaligned memory access
335 * - have to be careful of branch delay-slot instructions that fault
336 * SH3:
337 * - if the branch would be taken PC points to the branch
338 * - if the branch would not be taken, PC points to delay-slot
339 * SH4:
340 * - PC always points to delayed branch
341 * - return 0 if handled, -EFAULT if failed (may not return if in kernel)
342 */
343
344/* Macros to determine offset from current PC for branch instructions */
345/* Explicit type coercion is used to force sign extension where needed */
346#define SH_PC_8BIT_OFFSET(instr) ((((signed char)(instr))*2) + 4)
347#define SH_PC_12BIT_OFFSET(instr) ((((signed short)(instr<<4))>>3) + 4)
348
Paul Mundt710ee0c2006-11-05 16:48:42 +0900349/*
350 * XXX: SH-2A needs this too, but it needs an overhaul thanks to mixed 32-bit
351 * opcodes..
352 */
353#ifndef CONFIG_CPU_SH2A
354static int handle_unaligned_notify_count = 10;
355
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
357{
358 u_int rm;
359 int ret, index;
360
361 index = (instruction>>8)&15; /* 0x0F00 */
362 rm = regs->regs[index];
363
364 /* shout about the first ten userspace fixups */
365 if (user_mode(regs) && handle_unaligned_notify_count>0) {
366 handle_unaligned_notify_count--;
367
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900368 printk(KERN_NOTICE "Fixing up unaligned userspace access "
369 "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 current->comm,current->pid,(u16*)regs->pc,instruction);
371 }
372
373 ret = -EFAULT;
374 switch (instruction&0xF000) {
375 case 0x0000:
376 if (instruction==0x000B) {
377 /* rts */
378 ret = handle_unaligned_delayslot(regs);
379 if (ret==0)
380 regs->pc = regs->pr;
381 }
382 else if ((instruction&0x00FF)==0x0023) {
383 /* braf @Rm */
384 ret = handle_unaligned_delayslot(regs);
385 if (ret==0)
386 regs->pc += rm + 4;
387 }
388 else if ((instruction&0x00FF)==0x0003) {
389 /* bsrf @Rm */
390 ret = handle_unaligned_delayslot(regs);
391 if (ret==0) {
392 regs->pr = regs->pc + 4;
393 regs->pc += rm + 4;
394 }
395 }
396 else {
397 /* mov.[bwl] to/from memory via r0+rn */
398 goto simple;
399 }
400 break;
401
402 case 0x1000: /* mov.l Rm,@(disp,Rn) */
403 goto simple;
404
405 case 0x2000: /* mov.[bwl] to memory, possibly with pre-decrement */
406 goto simple;
407
408 case 0x4000:
409 if ((instruction&0x00FF)==0x002B) {
410 /* jmp @Rm */
411 ret = handle_unaligned_delayslot(regs);
412 if (ret==0)
413 regs->pc = rm;
414 }
415 else if ((instruction&0x00FF)==0x000B) {
416 /* jsr @Rm */
417 ret = handle_unaligned_delayslot(regs);
418 if (ret==0) {
419 regs->pr = regs->pc + 4;
420 regs->pc = rm;
421 }
422 }
423 else {
424 /* mov.[bwl] to/from memory via r0+rn */
425 goto simple;
426 }
427 break;
428
429 case 0x5000: /* mov.l @(disp,Rm),Rn */
430 goto simple;
431
432 case 0x6000: /* mov.[bwl] from memory, possibly with post-increment */
433 goto simple;
434
435 case 0x8000: /* bf lab, bf/s lab, bt lab, bt/s lab */
436 switch (instruction&0x0F00) {
437 case 0x0100: /* mov.w R0,@(disp,Rm) */
438 goto simple;
439 case 0x0500: /* mov.w @(disp,Rm),R0 */
440 goto simple;
441 case 0x0B00: /* bf lab - no delayslot*/
442 break;
443 case 0x0F00: /* bf/s lab */
444 ret = handle_unaligned_delayslot(regs);
445 if (ret==0) {
446#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)
447 if ((regs->sr & 0x00000001) != 0)
448 regs->pc += 4; /* next after slot */
449 else
450#endif
451 regs->pc += SH_PC_8BIT_OFFSET(instruction);
452 }
453 break;
454 case 0x0900: /* bt lab - no delayslot */
455 break;
456 case 0x0D00: /* bt/s lab */
457 ret = handle_unaligned_delayslot(regs);
458 if (ret==0) {
459#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)
460 if ((regs->sr & 0x00000001) == 0)
461 regs->pc += 4; /* next after slot */
462 else
463#endif
464 regs->pc += SH_PC_8BIT_OFFSET(instruction);
465 }
466 break;
467 }
468 break;
469
470 case 0xA000: /* bra label */
471 ret = handle_unaligned_delayslot(regs);
472 if (ret==0)
473 regs->pc += SH_PC_12BIT_OFFSET(instruction);
474 break;
475
476 case 0xB000: /* bsr label */
477 ret = handle_unaligned_delayslot(regs);
478 if (ret==0) {
479 regs->pr = regs->pc + 4;
480 regs->pc += SH_PC_12BIT_OFFSET(instruction);
481 }
482 break;
483 }
484 return ret;
485
486 /* handle non-delay-slot instruction */
487 simple:
488 ret = handle_unaligned_ins(instruction,regs);
489 if (ret==0)
490 regs->pc += 2;
491 return ret;
492}
Paul Mundt710ee0c2006-11-05 16:48:42 +0900493#endif /* CONFIG_CPU_SH2A */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494
Yoshinori Sato0983b312006-11-05 15:58:47 +0900495#ifdef CONFIG_CPU_HAS_SR_RB
496#define lookup_exception_vector(x) \
497 __asm__ __volatile__ ("stc r2_bank, %0\n\t" : "=r" ((x)))
498#else
499#define lookup_exception_vector(x) \
500 __asm__ __volatile__ ("mov r4, %0\n\t" : "=r" ((x)))
501#endif
502
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503/*
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900504 * Handle various address error exceptions:
505 * - instruction address error:
506 * misaligned PC
507 * PC >= 0x80000000 in user mode
508 * - data address error (read and write)
509 * misaligned data access
510 * access to >= 0x80000000 is user mode
511 * Unfortuntaly we can't distinguish between instruction address error
512 * and data address errors caused by read acceses.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 */
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900514asmlinkage void do_address_error(struct pt_regs *regs,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 unsigned long writeaccess,
516 unsigned long address)
517{
Yoshinori Sato0983b312006-11-05 15:58:47 +0900518 unsigned long error_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 mm_segment_t oldfs;
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900520 siginfo_t info;
Paul Mundt710ee0c2006-11-05 16:48:42 +0900521#ifndef CONFIG_CPU_SH2A
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 u16 instruction;
523 int tmp;
Paul Mundt710ee0c2006-11-05 16:48:42 +0900524#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525
Yoshinori Sato0983b312006-11-05 15:58:47 +0900526 /* Intentional ifdef */
527#ifdef CONFIG_CPU_HAS_SR_RB
528 lookup_exception_vector(error_code);
529#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530
531 oldfs = get_fs();
532
533 if (user_mode(regs)) {
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900534 int si_code = BUS_ADRERR;
535
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 local_irq_enable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537
538 /* bad PC is not something we can fix */
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900539 if (regs->pc & 1) {
540 si_code = BUS_ADRALN;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 goto uspace_segv;
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900542 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543
Yoshinori Sato0983b312006-11-05 15:58:47 +0900544#ifndef CONFIG_CPU_SH2A
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 set_fs(USER_DS);
546 if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) {
547 /* Argh. Fault on the instruction itself.
548 This should never happen non-SMP
549 */
550 set_fs(oldfs);
551 goto uspace_segv;
552 }
553
554 tmp = handle_unaligned_access(instruction, regs);
555 set_fs(oldfs);
556
557 if (tmp==0)
558 return; /* sorted */
Yoshinori Sato0983b312006-11-05 15:58:47 +0900559#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900561uspace_segv:
562 printk(KERN_NOTICE "Sending SIGBUS to \"%s\" due to unaligned "
563 "access (PC %lx PR %lx)\n", current->comm, regs->pc,
564 regs->pr);
565
566 info.si_signo = SIGBUS;
567 info.si_errno = 0;
568 info.si_code = si_code;
569 info.si_addr = (void *) address;
570 force_sig_info(SIGBUS, &info, current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 } else {
572 if (regs->pc & 1)
573 die("unaligned program counter", regs, error_code);
574
Yoshinori Sato0983b312006-11-05 15:58:47 +0900575#ifndef CONFIG_CPU_SH2A
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 set_fs(KERNEL_DS);
577 if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) {
578 /* Argh. Fault on the instruction itself.
579 This should never happen non-SMP
580 */
581 set_fs(oldfs);
582 die("insn faulting in do_address_error", regs, 0);
583 }
584
585 handle_unaligned_access(instruction, regs);
586 set_fs(oldfs);
Yoshinori Sato0983b312006-11-05 15:58:47 +0900587#else
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900588 printk(KERN_NOTICE "Killing process \"%s\" due to unaligned "
589 "access\n", current->comm);
590
Yoshinori Sato0983b312006-11-05 15:58:47 +0900591 force_sig(SIGSEGV, current);
592#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 }
594}
595
596#ifdef CONFIG_SH_DSP
597/*
598 * SH-DSP support gerg@snapgear.com.
599 */
600int is_dsp_inst(struct pt_regs *regs)
601{
602 unsigned short inst;
603
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900604 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 * Safe guard if DSP mode is already enabled or we're lacking
606 * the DSP altogether.
607 */
608 if (!(cpu_data->flags & CPU_HAS_DSP) || (regs->sr & SR_DSP))
609 return 0;
610
611 get_user(inst, ((unsigned short *) regs->pc));
612
613 inst &= 0xf000;
614
615 /* Check for any type of DSP or support instruction */
616 if ((inst == 0xf000) || (inst == 0x4000))
617 return 1;
618
619 return 0;
620}
621#else
622#define is_dsp_inst(regs) (0)
623#endif /* CONFIG_SH_DSP */
624
Yoshinori Sato0983b312006-11-05 15:58:47 +0900625#ifdef CONFIG_CPU_SH2A
626asmlinkage void do_divide_error(unsigned long r4, unsigned long r5,
627 unsigned long r6, unsigned long r7,
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900628 struct pt_regs __regs)
Yoshinori Sato0983b312006-11-05 15:58:47 +0900629{
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900630 struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
Yoshinori Sato0983b312006-11-05 15:58:47 +0900631 siginfo_t info;
632
Yoshinori Sato0983b312006-11-05 15:58:47 +0900633 switch (r4) {
634 case TRAP_DIVZERO_ERROR:
635 info.si_code = FPE_INTDIV;
636 break;
637 case TRAP_DIVOVF_ERROR:
638 info.si_code = FPE_INTOVF;
639 break;
640 }
641
642 force_sig_info(SIGFPE, &info, current);
643}
644#endif
645
Paul Mundt1f666582006-10-19 16:20:25 +0900646/* arch/sh/kernel/cpu/sh4/fpu.c */
647extern int do_fpu_inst(unsigned short, struct pt_regs *);
648extern asmlinkage void do_fpu_state_restore(unsigned long r4, unsigned long r5,
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900649 unsigned long r6, unsigned long r7, struct pt_regs __regs);
Takashi YOSHII4b565682006-09-27 17:15:32 +0900650
651asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5,
652 unsigned long r6, unsigned long r7,
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900653 struct pt_regs __regs)
Takashi YOSHII4b565682006-09-27 17:15:32 +0900654{
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900655 struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
Takashi YOSHII4b565682006-09-27 17:15:32 +0900656 unsigned long error_code;
657 struct task_struct *tsk = current;
658
659#ifdef CONFIG_SH_FPU_EMU
Yoshinori Sato0983b312006-11-05 15:58:47 +0900660 unsigned short inst = 0;
Takashi YOSHII4b565682006-09-27 17:15:32 +0900661 int err;
662
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900663 get_user(inst, (unsigned short*)regs->pc);
Takashi YOSHII4b565682006-09-27 17:15:32 +0900664
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900665 err = do_fpu_inst(inst, regs);
Takashi YOSHII4b565682006-09-27 17:15:32 +0900666 if (!err) {
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900667 regs->pc += 2;
Takashi YOSHII4b565682006-09-27 17:15:32 +0900668 return;
669 }
670 /* not a FPU inst. */
671#endif
672
673#ifdef CONFIG_SH_DSP
674 /* Check if it's a DSP instruction */
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900675 if (is_dsp_inst(regs)) {
Takashi YOSHII4b565682006-09-27 17:15:32 +0900676 /* Enable DSP mode, and restart instruction. */
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900677 regs->sr |= SR_DSP;
Takashi YOSHII4b565682006-09-27 17:15:32 +0900678 return;
679 }
680#endif
681
Yoshinori Sato0983b312006-11-05 15:58:47 +0900682 lookup_exception_vector(error_code);
683
Takashi YOSHII4b565682006-09-27 17:15:32 +0900684 local_irq_enable();
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900685 CHK_REMOTE_DEBUG(regs);
Takashi YOSHII4b565682006-09-27 17:15:32 +0900686 force_sig(SIGILL, tsk);
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900687 die_if_no_fixup("reserved instruction", regs, error_code);
Takashi YOSHII4b565682006-09-27 17:15:32 +0900688}
689
690#ifdef CONFIG_SH_FPU_EMU
691static int emulate_branch(unsigned short inst, struct pt_regs* regs)
692{
693 /*
694 * bfs: 8fxx: PC+=d*2+4;
695 * bts: 8dxx: PC+=d*2+4;
696 * bra: axxx: PC+=D*2+4;
697 * bsr: bxxx: PC+=D*2+4 after PR=PC+4;
698 * braf:0x23: PC+=Rn*2+4;
699 * bsrf:0x03: PC+=Rn*2+4 after PR=PC+4;
700 * jmp: 4x2b: PC=Rn;
701 * jsr: 4x0b: PC=Rn after PR=PC+4;
702 * rts: 000b: PC=PR;
703 */
704 if ((inst & 0xfd00) == 0x8d00) {
705 regs->pc += SH_PC_8BIT_OFFSET(inst);
706 return 0;
707 }
708
709 if ((inst & 0xe000) == 0xa000) {
710 regs->pc += SH_PC_12BIT_OFFSET(inst);
711 return 0;
712 }
713
714 if ((inst & 0xf0df) == 0x0003) {
715 regs->pc += regs->regs[(inst & 0x0f00) >> 8] + 4;
716 return 0;
717 }
718
719 if ((inst & 0xf0df) == 0x400b) {
720 regs->pc = regs->regs[(inst & 0x0f00) >> 8];
721 return 0;
722 }
723
724 if ((inst & 0xffff) == 0x000b) {
725 regs->pc = regs->pr;
726 return 0;
727 }
728
729 return 1;
730}
731#endif
732
733asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5,
734 unsigned long r6, unsigned long r7,
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900735 struct pt_regs __regs)
Takashi YOSHII4b565682006-09-27 17:15:32 +0900736{
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900737 struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
Takashi YOSHII4b565682006-09-27 17:15:32 +0900738 unsigned long error_code;
739 struct task_struct *tsk = current;
740#ifdef CONFIG_SH_FPU_EMU
Yoshinori Sato0983b312006-11-05 15:58:47 +0900741 unsigned short inst = 0;
Takashi YOSHII4b565682006-09-27 17:15:32 +0900742
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900743 get_user(inst, (unsigned short *)regs->pc + 1);
744 if (!do_fpu_inst(inst, regs)) {
745 get_user(inst, (unsigned short *)regs->pc);
746 if (!emulate_branch(inst, regs))
Takashi YOSHII4b565682006-09-27 17:15:32 +0900747 return;
748 /* fault in branch.*/
749 }
750 /* not a FPU inst. */
751#endif
752
Yoshinori Sato0983b312006-11-05 15:58:47 +0900753 lookup_exception_vector(error_code);
754
Takashi YOSHII4b565682006-09-27 17:15:32 +0900755 local_irq_enable();
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900756 CHK_REMOTE_DEBUG(regs);
Takashi YOSHII4b565682006-09-27 17:15:32 +0900757 force_sig(SIGILL, tsk);
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900758 die_if_no_fixup("illegal slot instruction", regs, error_code);
Takashi YOSHII4b565682006-09-27 17:15:32 +0900759}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760
761asmlinkage void do_exception_error(unsigned long r4, unsigned long r5,
762 unsigned long r6, unsigned long r7,
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900763 struct pt_regs __regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764{
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900765 struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 long ex;
Yoshinori Sato0983b312006-11-05 15:58:47 +0900767
768 lookup_exception_vector(ex);
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900769 die_if_kernel("exception", regs, ex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770}
771
772#if defined(CONFIG_SH_STANDARD_BIOS)
773void *gdb_vbr_vector;
774
775static inline void __init gdb_vbr_init(void)
776{
777 register unsigned long vbr;
778
779 /*
780 * Read the old value of the VBR register to initialise
781 * the vector through which debug and BIOS traps are
782 * delegated by the Linux trap handler.
783 */
784 asm volatile("stc vbr, %0" : "=r" (vbr));
785
786 gdb_vbr_vector = (void *)(vbr + 0x100);
787 printk("Setting GDB trap vector to 0x%08lx\n",
788 (unsigned long)gdb_vbr_vector);
789}
790#endif
791
792void __init per_cpu_trap_init(void)
793{
794 extern void *vbr_base;
795
796#ifdef CONFIG_SH_STANDARD_BIOS
797 gdb_vbr_init();
798#endif
799
800 /* NOTE: The VBR value should be at P1
801 (or P2, virtural "fixed" address space).
802 It's definitely should not in physical address. */
803
804 asm volatile("ldc %0, vbr"
805 : /* no output */
806 : "r" (&vbr_base)
807 : "memory");
808}
809
Paul Mundt1f666582006-10-19 16:20:25 +0900810void *set_exception_table_vec(unsigned int vec, void *handler)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811{
812 extern void *exception_handling_table[];
Paul Mundt1f666582006-10-19 16:20:25 +0900813 void *old_handler;
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900814
Paul Mundt1f666582006-10-19 16:20:25 +0900815 old_handler = exception_handling_table[vec];
816 exception_handling_table[vec] = handler;
817 return old_handler;
818}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819
Yoshinori Sato0983b312006-11-05 15:58:47 +0900820extern asmlinkage void address_error_handler(unsigned long r4, unsigned long r5,
821 unsigned long r6, unsigned long r7,
Stuart Menefyf0bc8142006-11-21 11:16:57 +0900822 struct pt_regs __regs);
Yoshinori Sato0983b312006-11-05 15:58:47 +0900823
Paul Mundt1f666582006-10-19 16:20:25 +0900824void __init trap_init(void)
825{
826 set_exception_table_vec(TRAP_RESERVED_INST, do_reserved_inst);
827 set_exception_table_vec(TRAP_ILLEGAL_SLOT_INST, do_illegal_slot_inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828
Takashi YOSHII4b565682006-09-27 17:15:32 +0900829#if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SH_FPU) || \
830 defined(CONFIG_SH_FPU_EMU)
831 /*
832 * For SH-4 lacking an FPU, treat floating point instructions as
833 * reserved. They'll be handled in the math-emu case, or faulted on
834 * otherwise.
835 */
Paul Mundt1f666582006-10-19 16:20:25 +0900836 set_exception_table_evt(0x800, do_reserved_inst);
837 set_exception_table_evt(0x820, do_illegal_slot_inst);
838#elif defined(CONFIG_SH_FPU)
839 set_exception_table_evt(0x800, do_fpu_state_restore);
840 set_exception_table_evt(0x820, do_fpu_state_restore);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841#endif
Yoshinori Sato0983b312006-11-05 15:58:47 +0900842
843#ifdef CONFIG_CPU_SH2
844 set_exception_table_vec(TRAP_ADDRESS_ERROR, address_error_handler);
845#endif
846#ifdef CONFIG_CPU_SH2A
847 set_exception_table_vec(TRAP_DIVZERO_ERROR, do_divide_error);
848 set_exception_table_vec(TRAP_DIVOVF_ERROR, do_divide_error);
849#endif
Stuart Menefyb5a1bcb2006-11-21 13:34:04 +0900850
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 /* Setup VBR for boot cpu */
852 per_cpu_trap_init();
853}
854
Paul Mundt6b002232006-10-12 17:07:45 +0900855void show_trace(struct task_struct *tsk, unsigned long *sp,
856 struct pt_regs *regs)
857{
858 unsigned long addr;
859
860 if (regs && user_mode(regs))
861 return;
862
863 printk("\nCall trace: ");
864#ifdef CONFIG_KALLSYMS
865 printk("\n");
866#endif
867
868 while (!kstack_end(sp)) {
869 addr = *sp++;
870 if (kernel_text_address(addr))
871 print_ip_sym(addr);
872 }
873
874 printk("\n");
875}
876
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877void show_stack(struct task_struct *tsk, unsigned long *sp)
878{
Paul Mundt6b002232006-10-12 17:07:45 +0900879 unsigned long stack;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880
Paul Mundta6a311392006-09-27 18:22:14 +0900881 if (!tsk)
882 tsk = current;
883 if (tsk == current)
884 sp = (unsigned long *)current_stack_pointer;
885 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 sp = (unsigned long *)tsk->thread.sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887
Paul Mundt6b002232006-10-12 17:07:45 +0900888 stack = (unsigned long)sp;
889 dump_mem("Stack: ", stack, THREAD_SIZE +
890 (unsigned long)task_stack_page(tsk));
891 show_trace(tsk, sp, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892}
893
894void dump_stack(void)
895{
896 show_stack(NULL, NULL);
897}
898EXPORT_SYMBOL(dump_stack);