Blackfin: add support for the DBGA (debug assert) pseudo insn
authorRobin Getz <robin.getz@analog.com>
Tue, 16 Mar 2010 14:40:17 +0000 (14:40 +0000)
committerMike Frysinger <vapier@gentoo.org>
Sat, 22 May 2010 18:18:56 +0000 (14:18 -0400)
A few pseudo debug insns exist to make testing of simulators easier.
Since these don't actually exist in the hardware, we have to have the
exception handler take care of emulating these.  This allows sim test
cases to be executed unmodified under Linux and thus simplify debugging
greatly.

Signed-off-by: Robin Getz <robin.getz@analog.com>
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
arch/blackfin/Kconfig.debug
arch/blackfin/include/asm/pseudo_instructions.h [new file with mode: 0644]
arch/blackfin/kernel/Makefile
arch/blackfin/kernel/pseudodbg.c [new file with mode: 0644]
arch/blackfin/kernel/traps.c

index aec89a5280b2249ef8890c14ddd96918de36838b..3c49f76b37bc398d3bfe3fc5ce7859bbfb9db4e9 100644 (file)
@@ -264,4 +264,13 @@ config BFIN_ISRAM_SELF_TEST
        help
          Run some self tests of the isram driver code at boot.
 
+config BFIN_PSEUDODBG_INSNS
+       bool "Support pseudo debug instructions"
+       default n
+       help
+         This option allows the kernel to emulate some pseudo instructions which
+         allow simulator test cases to be run under Linux with no changes.
+
+         Most people should say N here.
+
 endmenu
diff --git a/arch/blackfin/include/asm/pseudo_instructions.h b/arch/blackfin/include/asm/pseudo_instructions.h
new file mode 100644 (file)
index 0000000..7173719
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * header file for pseudo instructions
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _BLACKFIN_PSEUDO_
+#define _BLACKFIN_PSEUDO_
+
+#include <linux/types.h>
+#include <asm/ptrace.h>
+
+extern bool execute_pseudodbg_assert(struct pt_regs *fp, unsigned int opcode);
+
+#endif
index 2fc7f32ae32f9bc22f9287d3de488b1c3f30389e..30d0d1f01dc7f0c017245ae75c5ba2693d335e87 100644 (file)
@@ -31,6 +31,7 @@ obj-$(CONFIG_EARLY_PRINTK)           += early_printk.o
 obj-$(CONFIG_EARLY_PRINTK)           += shadow_console.o
 obj-$(CONFIG_STACKTRACE)             += stacktrace.o
 obj-$(CONFIG_DEBUG_VERBOSE)          += trace.o
+obj-$(CONFIG_BFIN_PSEUDODBG_INSNS)   += pseudodbg.o
 
 # the kgdb test puts code into L2 and without linker
 # relaxation, we need to force long calls to/from it
diff --git a/arch/blackfin/kernel/pseudodbg.c b/arch/blackfin/kernel/pseudodbg.c
new file mode 100644 (file)
index 0000000..4474b8d
--- /dev/null
@@ -0,0 +1,73 @@
+/* The fake debug assert instructions
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/ptrace.h>
+
+#define PseudoDbg_Assert_opcode         0xf0000000
+#define PseudoDbg_Assert_expected_bits  0
+#define PseudoDbg_Assert_expected_mask  0xffff
+#define PseudoDbg_Assert_regtest_bits   16
+#define PseudoDbg_Assert_regtest_mask   0x7
+#define PseudoDbg_Assert_grp_bits       19
+#define PseudoDbg_Assert_grp_mask       0x7
+#define PseudoDbg_Assert_dbgop_bits     22
+#define PseudoDbg_Assert_dbgop_mask     0x3
+#define PseudoDbg_Assert_dontcare_bits  24
+#define PseudoDbg_Assert_dontcare_mask  0x7
+#define PseudoDbg_Assert_code_bits      27
+#define PseudoDbg_Assert_code_mask      0x1f
+
+bool execute_pseudodbg_assert(struct pt_regs *fp, unsigned int opcode)
+{
+       int expected = ((opcode >> PseudoDbg_Assert_expected_bits) & PseudoDbg_Assert_expected_mask);
+       int dbgop    = ((opcode >> (PseudoDbg_Assert_dbgop_bits)) & PseudoDbg_Assert_dbgop_mask);
+       int grp      = ((opcode >> (PseudoDbg_Assert_grp_bits)) & PseudoDbg_Assert_grp_mask);
+       int regtest  = ((opcode >> (PseudoDbg_Assert_regtest_bits)) & PseudoDbg_Assert_regtest_mask);
+       long *value = &fp->r0;
+
+       if ((opcode & 0xFF000000) != PseudoDbg_Assert_opcode)
+               return false;
+
+       /* Only do Dregs and Pregs for now */
+       if (grp > 1)
+               return false;
+
+       /*
+        * Unfortunately, the pt_regs structure is not laid out the same way as the
+        * hardware register file, so we need to do some fix ups.
+        */
+       if (grp == 0 || (grp == 1 && regtest < 6))
+               value -= (regtest + 8 * grp);
+       else if (grp == 1 && regtest == 6)
+               value = &fp->usp;
+       else if (grp == 1 && regtest == 7)
+               value = &fp->fp;
+
+       if (dbgop == 0 || dbgop == 2) {
+               /* DBGA ( regs_lo , uimm16 ) */
+               /* DBGAL ( regs , uimm16 ) */
+               if (expected != (*value & 0xFFFF)) {
+                       pr_notice("DBGA (%s%i.L,0x%x) failure, got 0x%x\n", grp ? "P" : "R",
+                               regtest, expected, (unsigned int)(*value & 0xFFFF));
+                       return false;
+               }
+
+       } else if (dbgop == 1 || dbgop == 3) {
+               /* DBGA ( regs_hi , uimm16 ) */
+               /* DBGAH ( regs , uimm16 ) */
+               if (expected != ((*value >> 16) & 0xFFFF)) {
+                       pr_notice("DBGA (%s%i.H,0x%x) failure, got 0x%x\n", grp ? "P" : "R",
+                               regtest, expected, (unsigned int)((*value >> 16) & 0xFFFF));
+                       return false;
+               }
+       }
+
+       fp->pc += 4;
+       return true;
+}
index fffcf8a516bf868b9de2cf1d9d3c686ae663be11..9369836365bb72a2573774b84755868de4923f76 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/irq.h>
 #include <asm/trace.h>
 #include <asm/fixed_code.h>
+#include <asm/pseudo_instructions.h>
 
 #ifdef CONFIG_KGDB
 # include <linux/kgdb.h>
@@ -67,6 +68,9 @@ asmlinkage notrace void trap_c(struct pt_regs *fp)
 {
 #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
        int j;
+#endif
+#ifdef CONFIG_BFIN_PSEUDODBG_INSNS
+       int opcode;
 #endif
        unsigned int cpu = raw_smp_processor_id();
        const char *strerror = NULL;
@@ -199,6 +203,17 @@ asmlinkage notrace void trap_c(struct pt_regs *fp)
                                panic("BUG()");
                        }
                }
+#endif
+#ifdef CONFIG_BFIN_PSEUDODBG_INSNS
+               /*
+                * Support for the fake instructions, if the instruction fails,
+                * then just execute a illegal opcode failure (like normal).
+                * Don't support these instructions inside the kernel
+                */
+               if (!kernel_mode_regs(fp) && get_instruction(&opcode, (unsigned short *)fp->pc)) {
+                       if (execute_pseudodbg_assert(fp, opcode))
+                               goto traps_done;
+               }
 #endif
                info.si_code = ILL_ILLOPC;
                sig = SIGILL;