aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2007-05-08 01:50:59 -0400
committerPaul Mundt <lethal@hera.kernel.org>2007-05-08 21:35:01 -0400
commitbd0799977cb9b68aa6a39e9630aeea4778a58385 (patch)
tree125c0c923701c5b6f823a7b614c295e06370d46c
parent51c8b856f5edfa45d956721aa6d6ebaa15699062 (diff)
sh: Support for SH-2A 32-bit opcodes.
SH-2A supports both 16 and 32-bit instructions, add a simple helper for figuring out the instruction size in the places where there are hardcoded 16-bit assumptions. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
-rw-r--r--arch/sh/kernel/cpu/sh2a/Makefile5
-rw-r--r--arch/sh/kernel/cpu/sh2a/opcode_helper.c55
-rw-r--r--arch/sh/kernel/kgdb_stub.c2
-rw-r--r--arch/sh/kernel/process.c5
-rw-r--r--arch/sh/kernel/signal.c8
-rw-r--r--include/asm-sh/system.h9
6 files changed, 74 insertions, 10 deletions
diff --git a/arch/sh/kernel/cpu/sh2a/Makefile b/arch/sh/kernel/cpu/sh2a/Makefile
index 350972ae941..965fa2572b2 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
5obj-y := common.o probe.o 5obj-y := common.o probe.o opcode_helper.o
6 6
7common-y += $(addprefix ../sh2/, ex.o) 7common-y += $(addprefix ../sh2/, ex.o entry.o)
8common-y += $(addprefix ../sh2/, entry.o)
9 8
10obj-$(CONFIG_CPU_SUBTYPE_SH7206) += setup-sh7206.o clock-sh7206.o 9obj-$(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 00000000000..9704b7926d8
--- /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 */
38unsigned 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 a5323364cbc..ffe3e3ee580 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 4688b890aef..209cc9b4218 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
24static int hlt_counter; 25static 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 eb0191c374b..d7d98d691c6 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 e7e96ee0c8a..82f3e229e62 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
262extern 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 */