Root/
Source at commit 0de2b2b3be81048189a32f7a3d3ba0ba9ec817b6 created 11 years 11 months ago. By Maarten ter Huurne, MIPS: JZ4740: Fixed value for round robin constant. | |
---|---|
1 | /* |
2 | * 'traps.c' handles hardware traps and faults after we have saved some |
3 | * state in 'entry.S'. |
4 | * |
5 | * SuperH version: Copyright (C) 1999 Niibe Yutaka |
6 | * Copyright (C) 2000 Philipp Rumpf |
7 | * Copyright (C) 2000 David Howells |
8 | * Copyright (C) 2002 - 2010 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. |
13 | */ |
14 | #include <linux/kernel.h> |
15 | #include <linux/ptrace.h> |
16 | #include <linux/hardirq.h> |
17 | #include <linux/init.h> |
18 | #include <linux/spinlock.h> |
19 | #include <linux/module.h> |
20 | #include <linux/kallsyms.h> |
21 | #include <linux/io.h> |
22 | #include <linux/bug.h> |
23 | #include <linux/debug_locks.h> |
24 | #include <linux/kdebug.h> |
25 | #include <linux/kexec.h> |
26 | #include <linux/limits.h> |
27 | #include <linux/sysfs.h> |
28 | #include <linux/uaccess.h> |
29 | #include <linux/perf_event.h> |
30 | #include <asm/system.h> |
31 | #include <asm/alignment.h> |
32 | #include <asm/fpu.h> |
33 | #include <asm/kprobes.h> |
34 | |
35 | #ifdef CONFIG_CPU_SH2 |
36 | # 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_UBC 12 |
41 | # define TRAP_FPU_ERROR 13 |
42 | # define TRAP_DIVZERO_ERROR 17 |
43 | # define TRAP_DIVOVF_ERROR 18 |
44 | # endif |
45 | #else |
46 | #define TRAP_RESERVED_INST 12 |
47 | #define TRAP_ILLEGAL_SLOT_INST 13 |
48 | #endif |
49 | |
50 | static void dump_mem(const char *str, unsigned long bottom, unsigned long top) |
51 | { |
52 | unsigned long p; |
53 | int i; |
54 | |
55 | printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top); |
56 | |
57 | for (p = bottom & ~31; p < top; ) { |
58 | printk("%04lx: ", p & 0xffff); |
59 | |
60 | for (i = 0; i < 8; i++, p += 4) { |
61 | unsigned int val; |
62 | |
63 | if (p < bottom || p >= top) |
64 | printk(" "); |
65 | else { |
66 | if (__get_user(val, (unsigned int __user *)p)) { |
67 | printk("\n"); |
68 | return; |
69 | } |
70 | printk("%08x ", val); |
71 | } |
72 | } |
73 | printk("\n"); |
74 | } |
75 | } |
76 | |
77 | static DEFINE_SPINLOCK(die_lock); |
78 | |
79 | void die(const char * str, struct pt_regs * regs, long err) |
80 | { |
81 | static int die_counter; |
82 | |
83 | oops_enter(); |
84 | |
85 | spin_lock_irq(&die_lock); |
86 | console_verbose(); |
87 | bust_spinlocks(1); |
88 | |
89 | printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter); |
90 | print_modules(); |
91 | show_regs(regs); |
92 | |
93 | printk("Process: %s (pid: %d, stack limit = %p)\n", current->comm, |
94 | task_pid_nr(current), task_stack_page(current) + 1); |
95 | |
96 | if (!user_mode(regs) || in_interrupt()) |
97 | dump_mem("Stack: ", regs->regs[15], THREAD_SIZE + |
98 | (unsigned long)task_stack_page(current)); |
99 | |
100 | notify_die(DIE_OOPS, str, regs, err, 255, SIGSEGV); |
101 | |
102 | bust_spinlocks(0); |
103 | add_taint(TAINT_DIE); |
104 | spin_unlock_irq(&die_lock); |
105 | oops_exit(); |
106 | |
107 | if (kexec_should_crash(current)) |
108 | crash_kexec(regs); |
109 | |
110 | if (in_interrupt()) |
111 | panic("Fatal exception in interrupt"); |
112 | |
113 | if (panic_on_oops) |
114 | panic("Fatal exception"); |
115 | |
116 | do_exit(SIGSEGV); |
117 | } |
118 | |
119 | static inline void die_if_kernel(const char *str, struct pt_regs *regs, |
120 | long err) |
121 | { |
122 | if (!user_mode(regs)) |
123 | die(str, regs, err); |
124 | } |
125 | |
126 | /* |
127 | * try and fix up kernelspace address errors |
128 | * - userspace errors just cause EFAULT to be returned, resulting in SEGV |
129 | * - kernel/userspace interfaces cause a jump to an appropriate handler |
130 | * - other kernel errors are bad |
131 | */ |
132 | static void die_if_no_fixup(const char * str, struct pt_regs * regs, long err) |
133 | { |
134 | if (!user_mode(regs)) { |
135 | const struct exception_table_entry *fixup; |
136 | fixup = search_exception_tables(regs->pc); |
137 | if (fixup) { |
138 | regs->pc = fixup->fixup; |
139 | return; |
140 | } |
141 | |
142 | die(str, regs, err); |
143 | } |
144 | } |
145 | |
146 | static inline void sign_extend(unsigned int count, unsigned char *dst) |
147 | { |
148 | #ifdef __LITTLE_ENDIAN__ |
149 | if ((count == 1) && dst[0] & 0x80) { |
150 | dst[1] = 0xff; |
151 | dst[2] = 0xff; |
152 | dst[3] = 0xff; |
153 | } |
154 | if ((count == 2) && dst[1] & 0x80) { |
155 | dst[2] = 0xff; |
156 | dst[3] = 0xff; |
157 | } |
158 | #else |
159 | if ((count == 1) && dst[3] & 0x80) { |
160 | dst[2] = 0xff; |
161 | dst[1] = 0xff; |
162 | dst[0] = 0xff; |
163 | } |
164 | if ((count == 2) && dst[2] & 0x80) { |
165 | dst[1] = 0xff; |
166 | dst[0] = 0xff; |
167 | } |
168 | #endif |
169 | } |
170 | |
171 | static struct mem_access user_mem_access = { |
172 | copy_from_user, |
173 | copy_to_user, |
174 | }; |
175 | |
176 | /* |
177 | * handle an instruction that does an unaligned memory access by emulating the |
178 | * desired behaviour |
179 | * - note that PC _may not_ point to the faulting instruction |
180 | * (if that instruction is in a branch delay slot) |
181 | * - return 0 if emulation okay, -EFAULT on existential error |
182 | */ |
183 | static int handle_unaligned_ins(insn_size_t instruction, struct pt_regs *regs, |
184 | struct mem_access *ma) |
185 | { |
186 | int ret, index, count; |
187 | unsigned long *rm, *rn; |
188 | unsigned char *src, *dst; |
189 | unsigned char __user *srcu, *dstu; |
190 | |
191 | index = (instruction>>8)&15; /* 0x0F00 */ |
192 | rn = ®s->regs[index]; |
193 | |
194 | index = (instruction>>4)&15; /* 0x00F0 */ |
195 | rm = ®s->regs[index]; |
196 | |
197 | count = 1<<(instruction&3); |
198 | |
199 | switch (count) { |
200 | case 1: inc_unaligned_byte_access(); break; |
201 | case 2: inc_unaligned_word_access(); break; |
202 | case 4: inc_unaligned_dword_access(); break; |
203 | case 8: inc_unaligned_multi_access(); break; |
204 | } |
205 | |
206 | ret = -EFAULT; |
207 | switch (instruction>>12) { |
208 | case 0: /* mov.[bwl] to/from memory via r0+rn */ |
209 | if (instruction & 8) { |
210 | /* from memory */ |
211 | srcu = (unsigned char __user *)*rm; |
212 | srcu += regs->regs[0]; |
213 | dst = (unsigned char *)rn; |
214 | *(unsigned long *)dst = 0; |
215 | |
216 | #if !defined(__LITTLE_ENDIAN__) |
217 | dst += 4-count; |
218 | #endif |
219 | if (ma->from(dst, srcu, count)) |
220 | goto fetch_fault; |
221 | |
222 | sign_extend(count, dst); |
223 | } else { |
224 | /* to memory */ |
225 | src = (unsigned char *)rm; |
226 | #if !defined(__LITTLE_ENDIAN__) |
227 | src += 4-count; |
228 | #endif |
229 | dstu = (unsigned char __user *)*rn; |
230 | dstu += regs->regs[0]; |
231 | |
232 | if (ma->to(dstu, src, count)) |
233 | goto fetch_fault; |
234 | } |
235 | ret = 0; |
236 | break; |
237 | |
238 | case 1: /* mov.l Rm,@(disp,Rn) */ |
239 | src = (unsigned char*) rm; |
240 | dstu = (unsigned char __user *)*rn; |
241 | dstu += (instruction&0x000F)<<2; |
242 | |
243 | if (ma->to(dstu, src, 4)) |
244 | goto fetch_fault; |
245 | ret = 0; |
246 | break; |
247 | |
248 | case 2: /* mov.[bwl] to memory, possibly with pre-decrement */ |
249 | if (instruction & 4) |
250 | *rn -= count; |
251 | src = (unsigned char*) rm; |
252 | dstu = (unsigned char __user *)*rn; |
253 | #if !defined(__LITTLE_ENDIAN__) |
254 | src += 4-count; |
255 | #endif |
256 | if (ma->to(dstu, src, count)) |
257 | goto fetch_fault; |
258 | ret = 0; |
259 | break; |
260 | |
261 | case 5: /* mov.l @(disp,Rm),Rn */ |
262 | srcu = (unsigned char __user *)*rm; |
263 | srcu += (instruction & 0x000F) << 2; |
264 | dst = (unsigned char *)rn; |
265 | *(unsigned long *)dst = 0; |
266 | |
267 | if (ma->from(dst, srcu, 4)) |
268 | goto fetch_fault; |
269 | ret = 0; |
270 | break; |
271 | |
272 | case 6: /* mov.[bwl] from memory, possibly with post-increment */ |
273 | srcu = (unsigned char __user *)*rm; |
274 | if (instruction & 4) |
275 | *rm += count; |
276 | dst = (unsigned char*) rn; |
277 | *(unsigned long*)dst = 0; |
278 | |
279 | #if !defined(__LITTLE_ENDIAN__) |
280 | dst += 4-count; |
281 | #endif |
282 | if (ma->from(dst, srcu, count)) |
283 | goto fetch_fault; |
284 | sign_extend(count, dst); |
285 | ret = 0; |
286 | break; |
287 | |
288 | case 8: |
289 | switch ((instruction&0xFF00)>>8) { |
290 | case 0x81: /* mov.w R0,@(disp,Rn) */ |
291 | src = (unsigned char *) ®s->regs[0]; |
292 | #if !defined(__LITTLE_ENDIAN__) |
293 | src += 2; |
294 | #endif |
295 | dstu = (unsigned char __user *)*rm; /* called Rn in the spec */ |
296 | dstu += (instruction & 0x000F) << 1; |
297 | |
298 | if (ma->to(dstu, src, 2)) |
299 | goto fetch_fault; |
300 | ret = 0; |
301 | break; |
302 | |
303 | case 0x85: /* mov.w @(disp,Rm),R0 */ |
304 | srcu = (unsigned char __user *)*rm; |
305 | srcu += (instruction & 0x000F) << 1; |
306 | dst = (unsigned char *) ®s->regs[0]; |
307 | *(unsigned long *)dst = 0; |
308 | |
309 | #if !defined(__LITTLE_ENDIAN__) |
310 | dst += 2; |
311 | #endif |
312 | if (ma->from(dst, srcu, 2)) |
313 | goto fetch_fault; |
314 | sign_extend(2, dst); |
315 | ret = 0; |
316 | break; |
317 | } |
318 | break; |
319 | |
320 | case 9: /* mov.w @(disp,PC),Rn */ |
321 | srcu = (unsigned char __user *)regs->pc; |
322 | srcu += 4; |
323 | srcu += (instruction & 0x00FF) << 1; |
324 | dst = (unsigned char *)rn; |
325 | *(unsigned long *)dst = 0; |
326 | |
327 | #if !defined(__LITTLE_ENDIAN__) |
328 | dst += 2; |
329 | #endif |
330 | |
331 | if (ma->from(dst, srcu, 2)) |
332 | goto fetch_fault; |
333 | sign_extend(2, dst); |
334 | ret = 0; |
335 | break; |
336 | |
337 | case 0xd: /* mov.l @(disp,PC),Rn */ |
338 | srcu = (unsigned char __user *)(regs->pc & ~0x3); |
339 | srcu += 4; |
340 | srcu += (instruction & 0x00FF) << 2; |
341 | dst = (unsigned char *)rn; |
342 | *(unsigned long *)dst = 0; |
343 | |
344 | if (ma->from(dst, srcu, 4)) |
345 | goto fetch_fault; |
346 | ret = 0; |
347 | break; |
348 | } |
349 | return ret; |
350 | |
351 | fetch_fault: |
352 | /* Argh. Address not only misaligned but also non-existent. |
353 | * Raise an EFAULT and see if it's trapped |
354 | */ |
355 | die_if_no_fixup("Fault in unaligned fixup", regs, 0); |
356 | return -EFAULT; |
357 | } |
358 | |
359 | /* |
360 | * emulate the instruction in the delay slot |
361 | * - fetches the instruction from PC+2 |
362 | */ |
363 | static inline int handle_delayslot(struct pt_regs *regs, |
364 | insn_size_t old_instruction, |
365 | struct mem_access *ma) |
366 | { |
367 | insn_size_t instruction; |
368 | void __user *addr = (void __user *)(regs->pc + |
369 | instruction_size(old_instruction)); |
370 | |
371 | if (copy_from_user(&instruction, addr, sizeof(instruction))) { |
372 | /* the instruction-fetch faulted */ |
373 | if (user_mode(regs)) |
374 | return -EFAULT; |
375 | |
376 | /* kernel */ |
377 | die("delay-slot-insn faulting in handle_unaligned_delayslot", |
378 | regs, 0); |
379 | } |
380 | |
381 | return handle_unaligned_ins(instruction, regs, ma); |
382 | } |
383 | |
384 | /* |
385 | * handle an instruction that does an unaligned memory access |
386 | * - have to be careful of branch delay-slot instructions that fault |
387 | * SH3: |
388 | * - if the branch would be taken PC points to the branch |
389 | * - if the branch would not be taken, PC points to delay-slot |
390 | * SH4: |
391 | * - PC always points to delayed branch |
392 | * - return 0 if handled, -EFAULT if failed (may not return if in kernel) |
393 | */ |
394 | |
395 | /* Macros to determine offset from current PC for branch instructions */ |
396 | /* Explicit type coercion is used to force sign extension where needed */ |
397 | #define SH_PC_8BIT_OFFSET(instr) ((((signed char)(instr))*2) + 4) |
398 | #define SH_PC_12BIT_OFFSET(instr) ((((signed short)(instr<<4))>>3) + 4) |
399 | |
400 | int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs, |
401 | struct mem_access *ma, int expected, |
402 | unsigned long address) |
403 | { |
404 | u_int rm; |
405 | int ret, index; |
406 | |
407 | /* |
408 | * XXX: We can't handle mixed 16/32-bit instructions yet |
409 | */ |
410 | if (instruction_size(instruction) != 2) |
411 | return -EINVAL; |
412 | |
413 | index = (instruction>>8)&15; /* 0x0F00 */ |
414 | rm = regs->regs[index]; |
415 | |
416 | /* |
417 | * Log the unexpected fixups, and then pass them on to perf. |
418 | * |
419 | * We intentionally don't report the expected cases to perf as |
420 | * otherwise the trapped I/O case will skew the results too much |
421 | * to be useful. |
422 | */ |
423 | if (!expected) { |
424 | unaligned_fixups_notify(current, instruction, regs); |
425 | perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, |
426 | regs, address); |
427 | } |
428 | |
429 | ret = -EFAULT; |
430 | switch (instruction&0xF000) { |
431 | case 0x0000: |
432 | if (instruction==0x000B) { |
433 | /* rts */ |
434 | ret = handle_delayslot(regs, instruction, ma); |
435 | if (ret==0) |
436 | regs->pc = regs->pr; |
437 | } |
438 | else if ((instruction&0x00FF)==0x0023) { |
439 | /* braf @Rm */ |
440 | ret = handle_delayslot(regs, instruction, ma); |
441 | if (ret==0) |
442 | regs->pc += rm + 4; |
443 | } |
444 | else if ((instruction&0x00FF)==0x0003) { |
445 | /* bsrf @Rm */ |
446 | ret = handle_delayslot(regs, instruction, ma); |
447 | if (ret==0) { |
448 | regs->pr = regs->pc + 4; |
449 | regs->pc += rm + 4; |
450 | } |
451 | } |
452 | else { |
453 | /* mov.[bwl] to/from memory via r0+rn */ |
454 | goto simple; |
455 | } |
456 | break; |
457 | |
458 | case 0x1000: /* mov.l Rm,@(disp,Rn) */ |
459 | goto simple; |
460 | |
461 | case 0x2000: /* mov.[bwl] to memory, possibly with pre-decrement */ |
462 | goto simple; |
463 | |
464 | case 0x4000: |
465 | if ((instruction&0x00FF)==0x002B) { |
466 | /* jmp @Rm */ |
467 | ret = handle_delayslot(regs, instruction, ma); |
468 | if (ret==0) |
469 | regs->pc = rm; |
470 | } |
471 | else if ((instruction&0x00FF)==0x000B) { |
472 | /* jsr @Rm */ |
473 | ret = handle_delayslot(regs, instruction, ma); |
474 | if (ret==0) { |
475 | regs->pr = regs->pc + 4; |
476 | regs->pc = rm; |
477 | } |
478 | } |
479 | else { |
480 | /* mov.[bwl] to/from memory via r0+rn */ |
481 | goto simple; |
482 | } |
483 | break; |
484 | |
485 | case 0x5000: /* mov.l @(disp,Rm),Rn */ |
486 | goto simple; |
487 | |
488 | case 0x6000: /* mov.[bwl] from memory, possibly with post-increment */ |
489 | goto simple; |
490 | |
491 | case 0x8000: /* bf lab, bf/s lab, bt lab, bt/s lab */ |
492 | switch (instruction&0x0F00) { |
493 | case 0x0100: /* mov.w R0,@(disp,Rm) */ |
494 | goto simple; |
495 | case 0x0500: /* mov.w @(disp,Rm),R0 */ |
496 | goto simple; |
497 | case 0x0B00: /* bf lab - no delayslot*/ |
498 | ret = 0; |
499 | break; |
500 | case 0x0F00: /* bf/s lab */ |
501 | ret = handle_delayslot(regs, instruction, ma); |
502 | if (ret==0) { |
503 | #if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB) |
504 | if ((regs->sr & 0x00000001) != 0) |
505 | regs->pc += 4; /* next after slot */ |
506 | else |
507 | #endif |
508 | regs->pc += SH_PC_8BIT_OFFSET(instruction); |
509 | } |
510 | break; |
511 | case 0x0900: /* bt lab - no delayslot */ |
512 | ret = 0; |
513 | break; |
514 | case 0x0D00: /* bt/s lab */ |
515 | ret = handle_delayslot(regs, instruction, ma); |
516 | if (ret==0) { |
517 | #if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB) |
518 | if ((regs->sr & 0x00000001) == 0) |
519 | regs->pc += 4; /* next after slot */ |
520 | else |
521 | #endif |
522 | regs->pc += SH_PC_8BIT_OFFSET(instruction); |
523 | } |
524 | break; |
525 | } |
526 | break; |
527 | |
528 | case 0x9000: /* mov.w @(disp,Rm),Rn */ |
529 | goto simple; |
530 | |
531 | case 0xA000: /* bra label */ |
532 | ret = handle_delayslot(regs, instruction, ma); |
533 | if (ret==0) |
534 | regs->pc += SH_PC_12BIT_OFFSET(instruction); |
535 | break; |
536 | |
537 | case 0xB000: /* bsr label */ |
538 | ret = handle_delayslot(regs, instruction, ma); |
539 | if (ret==0) { |
540 | regs->pr = regs->pc + 4; |
541 | regs->pc += SH_PC_12BIT_OFFSET(instruction); |
542 | } |
543 | break; |
544 | |
545 | case 0xD000: /* mov.l @(disp,Rm),Rn */ |
546 | goto simple; |
547 | } |
548 | return ret; |
549 | |
550 | /* handle non-delay-slot instruction */ |
551 | simple: |
552 | ret = handle_unaligned_ins(instruction, regs, ma); |
553 | if (ret==0) |
554 | regs->pc += instruction_size(instruction); |
555 | return ret; |
556 | } |
557 | |
558 | /* |
559 | * Handle various address error exceptions: |
560 | * - instruction address error: |
561 | * misaligned PC |
562 | * PC >= 0x80000000 in user mode |
563 | * - data address error (read and write) |
564 | * misaligned data access |
565 | * access to >= 0x80000000 is user mode |
566 | * Unfortuntaly we can't distinguish between instruction address error |
567 | * and data address errors caused by read accesses. |
568 | */ |
569 | asmlinkage void do_address_error(struct pt_regs *regs, |
570 | unsigned long writeaccess, |
571 | unsigned long address) |
572 | { |
573 | unsigned long error_code = 0; |
574 | mm_segment_t oldfs; |
575 | siginfo_t info; |
576 | insn_size_t instruction; |
577 | int tmp; |
578 | |
579 | /* Intentional ifdef */ |
580 | #ifdef CONFIG_CPU_HAS_SR_RB |
581 | error_code = lookup_exception_vector(); |
582 | #endif |
583 | |
584 | oldfs = get_fs(); |
585 | |
586 | if (user_mode(regs)) { |
587 | int si_code = BUS_ADRERR; |
588 | unsigned int user_action; |
589 | |
590 | local_irq_enable(); |
591 | inc_unaligned_user_access(); |
592 | |
593 | set_fs(USER_DS); |
594 | if (copy_from_user(&instruction, (insn_size_t *)(regs->pc & ~1), |
595 | sizeof(instruction))) { |
596 | set_fs(oldfs); |
597 | goto uspace_segv; |
598 | } |
599 | set_fs(oldfs); |
600 | |
601 | /* shout about userspace fixups */ |
602 | unaligned_fixups_notify(current, instruction, regs); |
603 | |
604 | user_action = unaligned_user_action(); |
605 | if (user_action & UM_FIXUP) |
606 | goto fixup; |
607 | if (user_action & UM_SIGNAL) |
608 | goto uspace_segv; |
609 | else { |
610 | /* ignore */ |
611 | regs->pc += instruction_size(instruction); |
612 | return; |
613 | } |
614 | |
615 | fixup: |
616 | /* bad PC is not something we can fix */ |
617 | if (regs->pc & 1) { |
618 | si_code = BUS_ADRALN; |
619 | goto uspace_segv; |
620 | } |
621 | |
622 | set_fs(USER_DS); |
623 | tmp = handle_unaligned_access(instruction, regs, |
624 | &user_mem_access, 0, |
625 | address); |
626 | set_fs(oldfs); |
627 | |
628 | if (tmp == 0) |
629 | return; /* sorted */ |
630 | uspace_segv: |
631 | printk(KERN_NOTICE "Sending SIGBUS to \"%s\" due to unaligned " |
632 | "access (PC %lx PR %lx)\n", current->comm, regs->pc, |
633 | regs->pr); |
634 | |
635 | info.si_signo = SIGBUS; |
636 | info.si_errno = 0; |
637 | info.si_code = si_code; |
638 | info.si_addr = (void __user *)address; |
639 | force_sig_info(SIGBUS, &info, current); |
640 | } else { |
641 | inc_unaligned_kernel_access(); |
642 | |
643 | if (regs->pc & 1) |
644 | die("unaligned program counter", regs, error_code); |
645 | |
646 | set_fs(KERNEL_DS); |
647 | if (copy_from_user(&instruction, (void __user *)(regs->pc), |
648 | sizeof(instruction))) { |
649 | /* Argh. Fault on the instruction itself. |
650 | This should never happen non-SMP |
651 | */ |
652 | set_fs(oldfs); |
653 | die("insn faulting in do_address_error", regs, 0); |
654 | } |
655 | |
656 | unaligned_fixups_notify(current, instruction, regs); |
657 | |
658 | handle_unaligned_access(instruction, regs, &user_mem_access, |
659 | 0, address); |
660 | set_fs(oldfs); |
661 | } |
662 | } |
663 | |
664 | #ifdef CONFIG_SH_DSP |
665 | /* |
666 | * SH-DSP support gerg@snapgear.com. |
667 | */ |
668 | int is_dsp_inst(struct pt_regs *regs) |
669 | { |
670 | unsigned short inst = 0; |
671 | |
672 | /* |
673 | * Safe guard if DSP mode is already enabled or we're lacking |
674 | * the DSP altogether. |
675 | */ |
676 | if (!(current_cpu_data.flags & CPU_HAS_DSP) || (regs->sr & SR_DSP)) |
677 | return 0; |
678 | |
679 | get_user(inst, ((unsigned short *) regs->pc)); |
680 | |
681 | inst &= 0xf000; |
682 | |
683 | /* Check for any type of DSP or support instruction */ |
684 | if ((inst == 0xf000) || (inst == 0x4000)) |
685 | return 1; |
686 | |
687 | return 0; |
688 | } |
689 | #else |
690 | #define is_dsp_inst(regs) (0) |
691 | #endif /* CONFIG_SH_DSP */ |
692 | |
693 | #ifdef CONFIG_CPU_SH2A |
694 | asmlinkage void do_divide_error(unsigned long r4, unsigned long r5, |
695 | unsigned long r6, unsigned long r7, |
696 | struct pt_regs __regs) |
697 | { |
698 | siginfo_t info; |
699 | |
700 | switch (r4) { |
701 | case TRAP_DIVZERO_ERROR: |
702 | info.si_code = FPE_INTDIV; |
703 | break; |
704 | case TRAP_DIVOVF_ERROR: |
705 | info.si_code = FPE_INTOVF; |
706 | break; |
707 | } |
708 | |
709 | force_sig_info(SIGFPE, &info, current); |
710 | } |
711 | #endif |
712 | |
713 | asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5, |
714 | unsigned long r6, unsigned long r7, |
715 | struct pt_regs __regs) |
716 | { |
717 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); |
718 | unsigned long error_code; |
719 | struct task_struct *tsk = current; |
720 | |
721 | #ifdef CONFIG_SH_FPU_EMU |
722 | unsigned short inst = 0; |
723 | int err; |
724 | |
725 | get_user(inst, (unsigned short*)regs->pc); |
726 | |
727 | err = do_fpu_inst(inst, regs); |
728 | if (!err) { |
729 | regs->pc += instruction_size(inst); |
730 | return; |
731 | } |
732 | /* not a FPU inst. */ |
733 | #endif |
734 | |
735 | #ifdef CONFIG_SH_DSP |
736 | /* Check if it's a DSP instruction */ |
737 | if (is_dsp_inst(regs)) { |
738 | /* Enable DSP mode, and restart instruction. */ |
739 | regs->sr |= SR_DSP; |
740 | /* Save DSP mode */ |
741 | tsk->thread.dsp_status.status |= SR_DSP; |
742 | return; |
743 | } |
744 | #endif |
745 | |
746 | error_code = lookup_exception_vector(); |
747 | |
748 | local_irq_enable(); |
749 | force_sig(SIGILL, tsk); |
750 | die_if_no_fixup("reserved instruction", regs, error_code); |
751 | } |
752 | |
753 | #ifdef CONFIG_SH_FPU_EMU |
754 | static int emulate_branch(unsigned short inst, struct pt_regs *regs) |
755 | { |
756 | /* |
757 | * bfs: 8fxx: PC+=d*2+4; |
758 | * bts: 8dxx: PC+=d*2+4; |
759 | * bra: axxx: PC+=D*2+4; |
760 | * bsr: bxxx: PC+=D*2+4 after PR=PC+4; |
761 | * braf:0x23: PC+=Rn*2+4; |
762 | * bsrf:0x03: PC+=Rn*2+4 after PR=PC+4; |
763 | * jmp: 4x2b: PC=Rn; |
764 | * jsr: 4x0b: PC=Rn after PR=PC+4; |
765 | * rts: 000b: PC=PR; |
766 | */ |
767 | if (((inst & 0xf000) == 0xb000) || /* bsr */ |
768 | ((inst & 0xf0ff) == 0x0003) || /* bsrf */ |
769 | ((inst & 0xf0ff) == 0x400b)) /* jsr */ |
770 | regs->pr = regs->pc + 4; |
771 | |
772 | if ((inst & 0xfd00) == 0x8d00) { /* bfs, bts */ |
773 | regs->pc += SH_PC_8BIT_OFFSET(inst); |
774 | return 0; |
775 | } |
776 | |
777 | if ((inst & 0xe000) == 0xa000) { /* bra, bsr */ |
778 | regs->pc += SH_PC_12BIT_OFFSET(inst); |
779 | return 0; |
780 | } |
781 | |
782 | if ((inst & 0xf0df) == 0x0003) { /* braf, bsrf */ |
783 | regs->pc += regs->regs[(inst & 0x0f00) >> 8] + 4; |
784 | return 0; |
785 | } |
786 | |
787 | if ((inst & 0xf0df) == 0x400b) { /* jmp, jsr */ |
788 | regs->pc = regs->regs[(inst & 0x0f00) >> 8]; |
789 | return 0; |
790 | } |
791 | |
792 | if ((inst & 0xffff) == 0x000b) { /* rts */ |
793 | regs->pc = regs->pr; |
794 | return 0; |
795 | } |
796 | |
797 | return 1; |
798 | } |
799 | #endif |
800 | |
801 | asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5, |
802 | unsigned long r6, unsigned long r7, |
803 | struct pt_regs __regs) |
804 | { |
805 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); |
806 | unsigned long inst; |
807 | struct task_struct *tsk = current; |
808 | |
809 | if (kprobe_handle_illslot(regs->pc) == 0) |
810 | return; |
811 | |
812 | #ifdef CONFIG_SH_FPU_EMU |
813 | get_user(inst, (unsigned short *)regs->pc + 1); |
814 | if (!do_fpu_inst(inst, regs)) { |
815 | get_user(inst, (unsigned short *)regs->pc); |
816 | if (!emulate_branch(inst, regs)) |
817 | return; |
818 | /* fault in branch.*/ |
819 | } |
820 | /* not a FPU inst. */ |
821 | #endif |
822 | |
823 | inst = lookup_exception_vector(); |
824 | |
825 | local_irq_enable(); |
826 | force_sig(SIGILL, tsk); |
827 | die_if_no_fixup("illegal slot instruction", regs, inst); |
828 | } |
829 | |
830 | asmlinkage void do_exception_error(unsigned long r4, unsigned long r5, |
831 | unsigned long r6, unsigned long r7, |
832 | struct pt_regs __regs) |
833 | { |
834 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); |
835 | long ex; |
836 | |
837 | ex = lookup_exception_vector(); |
838 | die_if_kernel("exception", regs, ex); |
839 | } |
840 | |
841 | void __cpuinit per_cpu_trap_init(void) |
842 | { |
843 | extern void *vbr_base; |
844 | |
845 | /* NOTE: The VBR value should be at P1 |
846 | (or P2, virtural "fixed" address space). |
847 | It's definitely should not in physical address. */ |
848 | |
849 | asm volatile("ldc %0, vbr" |
850 | : /* no output */ |
851 | : "r" (&vbr_base) |
852 | : "memory"); |
853 | |
854 | /* disable exception blocking now when the vbr has been setup */ |
855 | clear_bl_bit(); |
856 | } |
857 | |
858 | void *set_exception_table_vec(unsigned int vec, void *handler) |
859 | { |
860 | extern void *exception_handling_table[]; |
861 | void *old_handler; |
862 | |
863 | old_handler = exception_handling_table[vec]; |
864 | exception_handling_table[vec] = handler; |
865 | return old_handler; |
866 | } |
867 | |
868 | void __init trap_init(void) |
869 | { |
870 | set_exception_table_vec(TRAP_RESERVED_INST, do_reserved_inst); |
871 | set_exception_table_vec(TRAP_ILLEGAL_SLOT_INST, do_illegal_slot_inst); |
872 | |
873 | #if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SH_FPU) || \ |
874 | defined(CONFIG_SH_FPU_EMU) |
875 | /* |
876 | * For SH-4 lacking an FPU, treat floating point instructions as |
877 | * reserved. They'll be handled in the math-emu case, or faulted on |
878 | * otherwise. |
879 | */ |
880 | set_exception_table_evt(0x800, do_reserved_inst); |
881 | set_exception_table_evt(0x820, do_illegal_slot_inst); |
882 | #elif defined(CONFIG_SH_FPU) |
883 | set_exception_table_evt(0x800, fpu_state_restore_trap_handler); |
884 | set_exception_table_evt(0x820, fpu_state_restore_trap_handler); |
885 | #endif |
886 | |
887 | #ifdef CONFIG_CPU_SH2 |
888 | set_exception_table_vec(TRAP_ADDRESS_ERROR, address_error_trap_handler); |
889 | #endif |
890 | #ifdef CONFIG_CPU_SH2A |
891 | set_exception_table_vec(TRAP_DIVZERO_ERROR, do_divide_error); |
892 | set_exception_table_vec(TRAP_DIVOVF_ERROR, do_divide_error); |
893 | #ifdef CONFIG_SH_FPU |
894 | set_exception_table_vec(TRAP_FPU_ERROR, fpu_error_trap_handler); |
895 | #endif |
896 | #endif |
897 | |
898 | #ifdef TRAP_UBC |
899 | set_exception_table_vec(TRAP_UBC, breakpoint_trap_handler); |
900 | #endif |
901 | } |
902 | |
903 | void show_stack(struct task_struct *tsk, unsigned long *sp) |
904 | { |
905 | unsigned long stack; |
906 | |
907 | if (!tsk) |
908 | tsk = current; |
909 | if (tsk == current) |
910 | sp = (unsigned long *)current_stack_pointer; |
911 | else |
912 | sp = (unsigned long *)tsk->thread.sp; |
913 | |
914 | stack = (unsigned long)sp; |
915 | dump_mem("Stack: ", stack, THREAD_SIZE + |
916 | (unsigned long)task_stack_page(tsk)); |
917 | show_trace(tsk, sp, NULL); |
918 | } |
919 | |
920 | void dump_stack(void) |
921 | { |
922 | show_stack(NULL, NULL); |
923 | } |
924 | EXPORT_SYMBOL(dump_stack); |
925 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9