File: /usr/src/linux/arch/sh/kernel/traps.c
1 /* $Id: traps.c,v 1.14 2001/07/24 08:07:10 gniibe Exp $
2 *
3 * linux/arch/sh/traps.c
4 *
5 * SuperH version: Copyright (C) 1999 Niibe Yutaka
6 * Copyright (C) 2000 Philipp Rumpf
7 * Copyright (C) 2000 David Howells
8 */
9
10 /*
11 * 'Traps.c' handles hardware traps and faults after we have saved some
12 * state in 'entry.S'.
13 */
14 #include <linux/config.h>
15 #include <linux/sched.h>
16 #include <linux/kernel.h>
17 #include <linux/string.h>
18 #include <linux/errno.h>
19 #include <linux/ptrace.h>
20 #include <linux/timer.h>
21 #include <linux/mm.h>
22 #include <linux/smp.h>
23 #include <linux/smp_lock.h>
24 #include <linux/init.h>
25 #include <linux/delay.h>
26 #include <linux/spinlock.h>
27
28 #include <asm/system.h>
29 #include <asm/uaccess.h>
30 #include <asm/io.h>
31 #include <asm/atomic.h>
32 #include <asm/processor.h>
33
34 #define DO_ERROR(trapnr, signr, str, name, tsk) \
35 asmlinkage void do_##name(unsigned long r4, unsigned long r5, \
36 unsigned long r6, unsigned long r7, \
37 struct pt_regs regs) \
38 { \
39 unsigned long error_code; \
40 \
41 asm volatile("stc r2_bank, %0": "=r" (error_code)); \
42 sti(); \
43 tsk->thread.error_code = error_code; \
44 tsk->thread.trap_no = trapnr; \
45 force_sig(signr, tsk); \
46 die_if_no_fixup(str,®s,error_code); \
47 }
48
49 /*
50 * These constants are for searching for possible module text
51 * segments. VMALLOC_OFFSET comes from mm/vmalloc.c; MODULE_RANGE is
52 * a guess of how much space is likely to be vmalloced.
53 */
54 #define VMALLOC_OFFSET (8*1024*1024)
55 #define MODULE_RANGE (8*1024*1024)
56
57 spinlock_t die_lock;
58
59 void die(const char * str, struct pt_regs * regs, long err)
60 {
61 console_verbose();
62 spin_lock_irq(&die_lock);
63 printk("%s: %04lx\n", str, err & 0xffff);
64 show_regs(regs);
65 spin_unlock_irq(&die_lock);
66 do_exit(SIGSEGV);
67 }
68
69 static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err)
70 {
71 if (!user_mode(regs))
72 die(str, regs, err);
73 }
74
75 static int handle_unaligned_notify_count = 10;
76
77 /*
78 * try and fix up kernelspace address errors
79 * - userspace errors just cause EFAULT to be returned, resulting in SEGV
80 * - kernel/userspace interfaces cause a jump to an appropriate handler
81 * - other kernel errors are bad
82 * - return 0 if fixed-up, -EFAULT if non-fatal (to the kernel) fault
83 */
84 static int die_if_no_fixup(const char * str, struct pt_regs * regs, long err)
85 {
86 if (!user_mode(regs))
87 {
88 unsigned long fixup;
89 fixup = search_exception_table(regs->pc);
90 if (fixup) {
91 regs->pc = fixup;
92 return 0;
93 }
94 die(str, regs, err);
95 }
96 return -EFAULT;
97 }
98
99 /*
100 * handle an instruction that does an unaligned memory access by emulating the
101 * desired behaviour
102 * - note that PC _may not_ point to the faulting instruction
103 * (if that instruction is in a branch delay slot)
104 * - return 0 if emulation okay, -EFAULT on existential error
105 */
106 static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs)
107 {
108 int ret, index, count;
109 unsigned long *rm, *rn;
110 unsigned char *src, *dst;
111
112 index = (instruction>>8)&15; /* 0x0F00 */
113 rn = ®s->regs[index];
114
115 index = (instruction>>4)&15; /* 0x00F0 */
116 rm = ®s->regs[index];
117
118 count = 1<<(instruction&3);
119
120 ret = -EFAULT;
121 switch (instruction>>12) {
122 case 0: /* mov.[bwl] to/from memory via r0+rn */
123 if (instruction & 8) {
124 /* from memory */
125 src = (unsigned char*) *rm;
126 src += regs->regs[0];
127 dst = (unsigned char*) rn;
128 *(unsigned long*)dst = 0;
129
130 #ifdef __LITTLE_ENDIAN__
131 if (copy_from_user(dst, src, count))
132 goto fetch_fault;
133
134 if ((count == 2) && dst[1] & 0x80) {
135 dst[2] = 0xff;
136 dst[3] = 0xff;
137 }
138 #else
139 dst += 4-count;
140
141 if (__copy_user(dst, src, count))
142 goto fetch_fault;
143
144 if ((count == 2) && dst[2] & 0x80) {
145 dst[0] = 0xff;
146 dst[1] = 0xff;
147 }
148 #endif
149 } else {
150 /* to memory */
151 src = (unsigned char*) rm;
152 #if !defined(__LITTLE_ENDIAN__)
153 src += 4-count;
154 #endif
155 dst = (unsigned char*) *rn;
156 dst += regs->regs[0];
157
158 if (copy_to_user(dst, src, count))
159 goto fetch_fault;
160 }
161 ret = 0;
162 break;
163
164 case 1: /* mov.l Rm,@(disp,Rn) */
165 src = (unsigned char*) rm;
166 dst = (unsigned char*) *rn;
167 dst += (instruction&0x000F)<<2;
168
169 if (copy_to_user(dst,src,4))
170 goto fetch_fault;
171 ret = 0;
172 break;
173
174 case 2: /* mov.[bwl] to memory, possibly with pre-decrement */
175 if (instruction & 4)
176 *rn -= count;
177 src = (unsigned char*) rm;
178 dst = (unsigned char*) *rn;
179 #if !defined(__LITTLE_ENDIAN__)
180 src += 4-count;
181 #endif
182 if (copy_to_user(dst, src, count))
183 goto fetch_fault;
184 ret = 0;
185 break;
186
187 case 5: /* mov.l @(disp,Rm),Rn */
188 src = (unsigned char*) *rm;
189 src += (instruction&0x000F)<<2;
190 dst = (unsigned char*) rn;
191 *(unsigned long*)dst = 0;
192
193 if (copy_from_user(dst,src,4))
194 goto fetch_fault;
195 ret = 0;
196 break;
197
198 case 6: /* mov.[bwl] from memory, possibly with post-increment */
199 src = (unsigned char*) *rm;
200 if (instruction & 4)
201 *rm += count;
202 dst = (unsigned char*) rn;
203 *(unsigned long*)dst = 0;
204
205 #ifdef __LITTLE_ENDIAN__
206 if (copy_from_user(dst, src, count))
207 goto fetch_fault;
208
209 if ((count == 2) && dst[1] & 0x80) {
210 dst[2] = 0xff;
211 dst[3] = 0xff;
212 }
213 #else
214 dst += 4-count;
215
216 if (copy_from_user(dst, src, count))
217 goto fetch_fault;
218
219 if ((count == 2) && dst[2] & 0x80) {
220 dst[0] = 0xff;
221 dst[1] = 0xff;
222 }
223 #endif
224 ret = 0;
225 break;
226
227 case 8:
228 switch ((instruction&0xFF00)>>8) {
229 case 0x81: /* mov.w R0,@(disp,Rn) */
230 src = (unsigned char*) ®s->regs[0];
231 #if !defined(__LITTLE_ENDIAN__)
232 src += 2;
233 #endif
234 dst = (unsigned char*) *rm; /* called Rn in the spec */
235 dst += (instruction&0x000F)<<1;
236
237 if (copy_to_user(dst, src, 2))
238 goto fetch_fault;
239 ret = 0;
240 break;
241
242 case 0x85: /* mov.w @(disp,Rm),R0 */
243 src = (unsigned char*) *rm;
244 src += (instruction&0x000F)<<1;
245 dst = (unsigned char*) ®s->regs[0];
246 *(unsigned long*)dst = 0;
247
248 #if !defined(__LITTLE_ENDIAN__)
249 dst += 2;
250 #endif
251
252 if (copy_from_user(dst, src, 2))
253 goto fetch_fault;
254
255 #ifdef __LITTLE_ENDIAN__
256 if (dst[1] & 0x80) {
257 dst[2] = 0xff;
258 dst[3] = 0xff;
259 }
260 #else
261 if (dst[2] & 0x80) {
262 dst[0] = 0xff;
263 dst[1] = 0xff;
264 }
265 #endif
266 ret = 0;
267 break;
268 }
269 break;
270 }
271 return ret;
272
273 fetch_fault:
274 /* Argh. Address not only misaligned but also non-existent.
275 * Raise an EFAULT and see if it's trapped
276 */
277 return die_if_no_fixup("Fault in unaligned fixup", regs, 0);
278 }
279
280 /*
281 * emulate the instruction in the delay slot
282 * - fetches the instruction from PC+2
283 */
284 static inline int handle_unaligned_delayslot(struct pt_regs *regs)
285 {
286 u16 instruction;
287
288 if (copy_from_user(&instruction, (u16 *)(regs->pc+2), 2)) {
289 /* the instruction-fetch faulted */
290 if (user_mode(regs))
291 return -EFAULT;
292
293 /* kernel */
294 die("delay-slot-insn faulting in handle_unaligned_delayslot", regs, 0);
295 }
296
297 return handle_unaligned_ins(instruction,regs);
298 }
299
300 /*
301 * handle an instruction that does an unaligned memory access
302 * - have to be careful of branch delay-slot instructions that fault
303 * - if the branch would be taken PC points to the branch
304 * - if the branch would not be taken, PC points to delay-slot
305 * - return 0 if handled, -EFAULT if failed (may not return if in kernel)
306 */
307 static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
308 {
309 u_int rm;
310 int ret, index;
311
312 index = (instruction>>8)&15; /* 0x0F00 */
313 rm = regs->regs[index];
314
315 /* shout about the first ten userspace fixups */
316 if (user_mode(regs) && handle_unaligned_notify_count>0) {
317 handle_unaligned_notify_count--;
318
319 printk("Fixing up unaligned userspace access in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n",
320 current->comm,current->pid,(u16*)regs->pc,instruction);
321 }
322
323 ret = -EFAULT;
324 switch (instruction&0xF000) {
325 case 0x0000:
326 if (instruction==0x000B) {
327 /* rts */
328 ret = handle_unaligned_delayslot(regs);
329 if (ret==0)
330 regs->pc = regs->pr;
331 }
332 else if ((instruction&0x00FF)==0x0023) {
333 /* braf @Rm */
334 ret = handle_unaligned_delayslot(regs);
335 if (ret==0)
336 regs->pc += rm + 4;
337 }
338 else if ((instruction&0x00FF)==0x0003) {
339 /* bsrf @Rm */
340 ret = handle_unaligned_delayslot(regs);
341 if (ret==0) {
342 regs->pr = regs->pc + 4;
343 regs->pc += rm + 4;
344 }
345 }
346 else {
347 /* mov.[bwl] to/from memory via r0+rn */
348 goto simple;
349 }
350 break;
351
352 case 0x1000: /* mov.l Rm,@(disp,Rn) */
353 goto simple;
354
355 case 0x2000: /* mov.[bwl] to memory, possibly with pre-decrement */
356 goto simple;
357
358 case 0x4000:
359 if ((instruction&0x00FF)==0x002B) {
360 /* jmp @Rm */
361 ret = handle_unaligned_delayslot(regs);
362 if (ret==0)
363 regs->pc = rm;
364 }
365 else if ((instruction&0x00FF)==0x000B) {
366 /* jsr @Rm */
367 ret = handle_unaligned_delayslot(regs);
368 if (ret==0) {
369 regs->pr = regs->pc + 4;
370 regs->pc = rm;
371 }
372 }
373 else {
374 /* mov.[bwl] to/from memory via r0+rn */
375 goto simple;
376 }
377 break;
378
379 case 0x5000: /* mov.l @(disp,Rm),Rn */
380 goto simple;
381
382 case 0x6000: /* mov.[bwl] from memory, possibly with post-increment */
383 goto simple;
384
385 case 0x8000: /* bf lab, bf/s lab, bt lab, bt/s lab */
386 switch (instruction&0x0F00) {
387 case 0x0100: /* mov.w R0,@(disp,Rm) */
388 goto simple;
389 case 0x0500: /* mov.w @(disp,Rm),R0 */
390 goto simple;
391 case 0x0B00: /* bf lab - no delayslot*/
392 break;
393 case 0x0F00: /* bf/s lab */
394 ret = handle_unaligned_delayslot(regs);
395 if (ret==0)
396 regs->pc += (instruction&0x00FF)*2 + 4;
397 break;
398 case 0x0900: /* bt lab - no delayslot */
399 break;
400 case 0x0D00: /* bt/s lab */
401 ret = handle_unaligned_delayslot(regs);
402 if (ret==0)
403 regs->pc += (instruction&0x00FF)*2 + 4;
404 break;
405 }
406 break;
407
408 case 0xA000: /* bra label */
409 ret = handle_unaligned_delayslot(regs);
410 if (ret==0)
411 regs->pc += (instruction&0x0FFF)*2 + 4;
412 break;
413
414 case 0xB000: /* bsr label */
415 ret = handle_unaligned_delayslot(regs);
416 if (ret==0) {
417 regs->pr = regs->pc + 4;
418 regs->pc += (instruction&0x0FFF)*2 + 4;
419 }
420 break;
421 }
422 return ret;
423
424 /* handle non-delay-slot instruction */
425 simple:
426 ret = handle_unaligned_ins(instruction,regs);
427 if (ret==0)
428 regs->pc += 2;
429 return ret;
430 }
431
432 /*
433 * Handle various address error exceptions
434 */
435 asmlinkage void do_address_error(struct pt_regs *regs,
436 unsigned long writeaccess,
437 unsigned long address)
438 {
439 unsigned long error_code;
440 mm_segment_t oldfs;
441 u16 instruction;
442 int tmp;
443
444 asm volatile("stc r2_bank,%0": "=r" (error_code));
445
446 oldfs = get_fs();
447
448 if (user_mode(regs)) {
449 sti();
450 current->thread.error_code = error_code;
451 current->thread.trap_no = (writeaccess) ? 8 : 7;
452
453 /* bad PC is not something we can fix */
454 if (regs->pc & 1)
455 goto uspace_segv;
456
457 set_fs(USER_DS);
458 if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) {
459 /* Argh. Fault on the instruction itself.
460 This should never happen non-SMP
461 */
462 set_fs(oldfs);
463 goto uspace_segv;
464 }
465
466 tmp = handle_unaligned_access(instruction, regs);
467 set_fs(oldfs);
468
469 if (tmp==0)
470 return; /* sorted */
471
472 uspace_segv:
473 printk(KERN_NOTICE "Killing process \"%s\" due to unaligned access\n", current->comm);
474 force_sig(SIGSEGV, current);
475 } else {
476 if (regs->pc & 1)
477 die("unaligned program counter", regs, error_code);
478
479 set_fs(KERNEL_DS);
480 if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) {
481 /* Argh. Fault on the instruction itself.
482 This should never happen non-SMP
483 */
484 set_fs(oldfs);
485 die("insn faulting in do_address_error", regs, 0);
486 }
487
488 handle_unaligned_access(instruction, regs);
489 set_fs(oldfs);
490 }
491 }
492
493 DO_ERROR(12, SIGILL, "reserved instruction", reserved_inst, current)
494 DO_ERROR(13, SIGILL, "illegal slot instruction", illegal_slot_inst, current)
495
496 asmlinkage void do_exception_error(unsigned long r4, unsigned long r5,
497 unsigned long r6, unsigned long r7,
498 struct pt_regs regs)
499 {
500 long ex;
501 asm volatile("stc r2_bank, %0" : "=r" (ex));
502 die_if_kernel("exception", ®s, ex);
503 }
504
505 #if defined(CONFIG_SH_STANDARD_BIOS)
506 void *gdb_vbr_vector;
507 #endif
508
509 void __init trap_init(void)
510 {
511 extern void *vbr_base;
512 extern void *exception_handling_table[14];
513
514 exception_handling_table[12] = (void *)do_reserved_inst;
515 exception_handling_table[13] = (void *)do_illegal_slot_inst;
516
517 #if defined(CONFIG_SH_STANDARD_BIOS)
518 /*
519 * Read the old value of the VBR register to initialise
520 * the vector through which debug and BIOS traps are
521 * delegated by the Linux trap handler.
522 */
523 {
524 register unsigned long vbr;
525 asm volatile("stc vbr, %0" : "=r" (vbr));
526 gdb_vbr_vector = (void *)(vbr + 0x100);
527 printk("Setting GDB trap vector to 0x%08lx\n",
528 (unsigned long)gdb_vbr_vector);
529 }
530 #endif
531
532 /* NOTE: The VBR value should be at P1
533 (or P2, virtural "fixed" address space).
534 It's definitely should not in physical address. */
535
536 asm volatile("ldc %0, vbr"
537 : /* no output */
538 : "r" (&vbr_base)
539 : "memory");
540 }
541
542 void dump_stack(void)
543 {
544 unsigned long *start;
545 unsigned long *end;
546 unsigned long *p;
547
548 asm("mov r15, %0" : "=r" (start));
549 asm("stc r7_bank, %0" : "=r" (end));
550 end += 8192/4;
551
552 printk("%08lx:%08lx\n", (unsigned long)start, (unsigned long)end);
553 for (p=start; p < end; p++) {
554 extern long _text, _etext;
555 unsigned long v=*p;
556
557 if ((v >= (unsigned long )&_text)
558 && (v <= (unsigned long )&_etext)) {
559 printk("%08lx\n", v);
560 }
561 }
562 }
563