diff options
-rw-r--r-- | arch/sh/kernel/cpu/sh2a/Makefile | 5 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/sh2a/opcode_helper.c | 55 | ||||
-rw-r--r-- | arch/sh/kernel/kgdb_stub.c | 2 | ||||
-rw-r--r-- | arch/sh/kernel/process.c | 5 | ||||
-rw-r--r-- | arch/sh/kernel/signal.c | 8 | ||||
-rw-r--r-- | include/asm-sh/system.h | 9 |
6 files changed, 74 insertions, 10 deletions
diff --git a/arch/sh/kernel/cpu/sh2a/Makefile b/arch/sh/kernel/cpu/sh2a/Makefile index 350972ae9410..965fa2572b23 100644 --- a/arch/sh/kernel/cpu/sh2a/Makefile +++ b/arch/sh/kernel/cpu/sh2a/Makefile | |||
@@ -2,9 +2,8 @@ | |||
2 | # Makefile for the Linux/SuperH SH-2A backends. | 2 | # Makefile for the Linux/SuperH SH-2A backends. |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-y := common.o probe.o | 5 | obj-y := common.o probe.o opcode_helper.o |
6 | 6 | ||
7 | common-y += $(addprefix ../sh2/, ex.o) | 7 | common-y += $(addprefix ../sh2/, ex.o entry.o) |
8 | common-y += $(addprefix ../sh2/, entry.o) | ||
9 | 8 | ||
10 | obj-$(CONFIG_CPU_SUBTYPE_SH7206) += setup-sh7206.o clock-sh7206.o | 9 | obj-$(CONFIG_CPU_SUBTYPE_SH7206) += setup-sh7206.o clock-sh7206.o |
diff --git a/arch/sh/kernel/cpu/sh2a/opcode_helper.c b/arch/sh/kernel/cpu/sh2a/opcode_helper.c new file mode 100644 index 000000000000..9704b7926d8b --- /dev/null +++ b/arch/sh/kernel/cpu/sh2a/opcode_helper.c | |||
@@ -0,0 +1,55 @@ | |||
1 | /* | ||
2 | * arch/sh/kernel/cpu/sh2a/opcode_helper.c | ||
3 | * | ||
4 | * Helper for the SH-2A 32-bit opcodes. | ||
5 | * | ||
6 | * Copyright (C) 2007 Paul Mundt | ||
7 | * | ||
8 | * This file is subject to the terms and conditions of the GNU General Public | ||
9 | * License. See the file "COPYING" in the main directory of this archive | ||
10 | * for more details. | ||
11 | */ | ||
12 | #include <linux/kernel.h> | ||
13 | #include <asm/system.h> | ||
14 | |||
15 | /* | ||
16 | * Instructions on SH are generally fixed at 16-bits, however, SH-2A | ||
17 | * introduces some 32-bit instructions. Since there are no real | ||
18 | * constraints on their use (and they can be mixed and matched), we need | ||
19 | * to check the instruction encoding to work out if it's a true 32-bit | ||
20 | * instruction or not. | ||
21 | * | ||
22 | * Presently, 32-bit opcodes have only slight variations in what the | ||
23 | * actual encoding looks like in the first-half of the instruction, which | ||
24 | * makes it fairly straightforward to differentiate from the 16-bit ones. | ||
25 | * | ||
26 | * First 16-bits of encoding Used by | ||
27 | * | ||
28 | * 0011nnnnmmmm0001 mov.b, mov.w, mov.l, fmov.d, | ||
29 | * fmov.s, movu.b, movu.w | ||
30 | * | ||
31 | * 0011nnnn0iii1001 bclr.b, bld.b, bset.b, bst.b, band.b, | ||
32 | * bandnot.b, bldnot.b, bor.b, bornot.b, | ||
33 | * bxor.b | ||
34 | * | ||
35 | * 0000nnnniiii0000 movi20 | ||
36 | * 0000nnnniiii0001 movi20s | ||
37 | */ | ||
38 | unsigned int instruction_size(unsigned int insn) | ||
39 | { | ||
40 | /* Look for the common cases */ | ||
41 | switch ((insn & 0xf00f)) { | ||
42 | case 0x0000: /* movi20 */ | ||
43 | case 0x0001: /* movi20s */ | ||
44 | case 0x3001: /* 32-bit mov/fmov/movu variants */ | ||
45 | return 4; | ||
46 | } | ||
47 | |||
48 | /* And the special cases.. */ | ||
49 | switch ((insn & 0xf08f)) { | ||
50 | case 0x3009: /* 32-bit b*.b bit operations */ | ||
51 | return 4; | ||
52 | } | ||
53 | |||
54 | return 2; | ||
55 | } | ||
diff --git a/arch/sh/kernel/kgdb_stub.c b/arch/sh/kernel/kgdb_stub.c index a5323364cbca..ffe3e3ee580d 100644 --- a/arch/sh/kernel/kgdb_stub.c +++ b/arch/sh/kernel/kgdb_stub.c | |||
@@ -867,7 +867,7 @@ static void kgdb_command_loop(const int excep_code, const int trapa_value) | |||
867 | trap 0xff, since that indicates a compiled-in breakpoint which | 867 | trap 0xff, since that indicates a compiled-in breakpoint which |
868 | will not be replaced (and we would retake the trap forever) */ | 868 | will not be replaced (and we would retake the trap forever) */ |
869 | if ((excep_code == TRAP_VEC) && (trapa_value != (0x3c << 2))) | 869 | if ((excep_code == TRAP_VEC) && (trapa_value != (0x3c << 2))) |
870 | trap_registers.pc -= 2; | 870 | trap_registers.pc -= instruction_size(trap_registers.pc); |
871 | 871 | ||
872 | /* Undo any stepping we may have done */ | 872 | /* Undo any stepping we may have done */ |
873 | undo_single_step(); | 873 | undo_single_step(); |
diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c index 4688b890aef8..209cc9b42186 100644 --- a/arch/sh/kernel/process.c +++ b/arch/sh/kernel/process.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <asm/uaccess.h> | 19 | #include <asm/uaccess.h> |
20 | #include <asm/mmu_context.h> | 20 | #include <asm/mmu_context.h> |
21 | #include <asm/pgalloc.h> | 21 | #include <asm/pgalloc.h> |
22 | #include <asm/system.h> | ||
22 | #include <asm/ubc.h> | 23 | #include <asm/ubc.h> |
23 | 24 | ||
24 | static int hlt_counter; | 25 | static int hlt_counter; |
@@ -497,7 +498,7 @@ asmlinkage void debug_trap_handler(unsigned long r4, unsigned long r5, | |||
497 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); | 498 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); |
498 | 499 | ||
499 | /* Rewind */ | 500 | /* Rewind */ |
500 | regs->pc -= 2; | 501 | regs->pc -= instruction_size(regs->pc); |
501 | 502 | ||
502 | if (notify_die(DIE_TRAP, regs, regs->tra & 0xff, | 503 | if (notify_die(DIE_TRAP, regs, regs->tra & 0xff, |
503 | SIGTRAP) == NOTIFY_STOP) | 504 | SIGTRAP) == NOTIFY_STOP) |
@@ -516,7 +517,7 @@ asmlinkage void bug_trap_handler(unsigned long r4, unsigned long r5, | |||
516 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); | 517 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); |
517 | 518 | ||
518 | /* Rewind */ | 519 | /* Rewind */ |
519 | regs->pc -= 2; | 520 | regs->pc -= instruction_size(regs->pc); |
520 | 521 | ||
521 | if (notify_die(DIE_TRAP, regs, TRAPA_BUG_OPCODE & 0xff, | 522 | if (notify_die(DIE_TRAP, regs, TRAPA_BUG_OPCODE & 0xff, |
522 | SIGTRAP) == NOTIFY_STOP) | 523 | SIGTRAP) == NOTIFY_STOP) |
diff --git a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c index eb0191c374b6..d7d98d691c64 100644 --- a/arch/sh/kernel/signal.c +++ b/arch/sh/kernel/signal.c | |||
@@ -23,7 +23,7 @@ | |||
23 | #include <linux/personality.h> | 23 | #include <linux/personality.h> |
24 | #include <linux/binfmts.h> | 24 | #include <linux/binfmts.h> |
25 | #include <linux/freezer.h> | 25 | #include <linux/freezer.h> |
26 | 26 | #include <asm/system.h> | |
27 | #include <asm/ucontext.h> | 27 | #include <asm/ucontext.h> |
28 | #include <asm/uaccess.h> | 28 | #include <asm/uaccess.h> |
29 | #include <asm/pgtable.h> | 29 | #include <asm/pgtable.h> |
@@ -500,7 +500,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, | |||
500 | } | 500 | } |
501 | /* fallthrough */ | 501 | /* fallthrough */ |
502 | case -ERESTARTNOINTR: | 502 | case -ERESTARTNOINTR: |
503 | regs->pc -= 2; | 503 | regs->pc -= instruction_size(regs->pc); |
504 | } | 504 | } |
505 | } else { | 505 | } else { |
506 | /* gUSA handling */ | 506 | /* gUSA handling */ |
@@ -600,9 +600,9 @@ static void do_signal(struct pt_regs *regs, unsigned int save_r0) | |||
600 | regs->regs[0] == -ERESTARTSYS || | 600 | regs->regs[0] == -ERESTARTSYS || |
601 | regs->regs[0] == -ERESTARTNOINTR) { | 601 | regs->regs[0] == -ERESTARTNOINTR) { |
602 | regs->regs[0] = save_r0; | 602 | regs->regs[0] = save_r0; |
603 | regs->pc -= 2; | 603 | regs->pc -= instruction_size(regs->pc); |
604 | } else if (regs->regs[0] == -ERESTART_RESTARTBLOCK) { | 604 | } else if (regs->regs[0] == -ERESTART_RESTARTBLOCK) { |
605 | regs->pc -= 2; | 605 | regs->pc -= instruction_size(regs->pc); |
606 | regs->regs[3] = __NR_restart_syscall; | 606 | regs->regs[3] = __NR_restart_syscall; |
607 | } | 607 | } |
608 | } | 608 | } |
diff --git a/include/asm-sh/system.h b/include/asm-sh/system.h index e7e96ee0c8a5..82f3e229e621 100644 --- a/include/asm-sh/system.h +++ b/include/asm-sh/system.h | |||
@@ -255,6 +255,15 @@ static inline void *set_exception_table_evt(unsigned int evt, void *handler) | |||
255 | return set_exception_table_vec(evt >> 5, handler); | 255 | return set_exception_table_vec(evt >> 5, handler); |
256 | } | 256 | } |
257 | 257 | ||
258 | /* | ||
259 | * SH-2A has both 16 and 32-bit opcodes, do lame encoding checks. | ||
260 | */ | ||
261 | #ifdef CONFIG_CPU_SH2A | ||
262 | extern unsigned int instruction_size(unsigned int insn); | ||
263 | #else | ||
264 | #define instruction_size(insn) (2) | ||
265 | #endif | ||
266 | |||
258 | /* XXX | 267 | /* XXX |
259 | * disable hlt during certain critical i/o operations | 268 | * disable hlt during certain critical i/o operations |
260 | */ | 269 | */ |