Skip to content

Commit

Permalink
Blackfin: add support for the DBGA (debug assert) pseudo insn
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Robin Getz authored and Mike Frysinger committed May 22, 2010
1 parent 2620c83 commit 6ce3e9c
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 0 deletions.
9 changes: 9 additions & 0 deletions arch/blackfin/Kconfig.debug
Original file line number Diff line number Diff line change
Expand Up @@ -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
17 changes: 17 additions & 0 deletions arch/blackfin/include/asm/pseudo_instructions.h
Original file line number Diff line number Diff line change
@@ -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
1 change: 1 addition & 0 deletions arch/blackfin/kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
73 changes: 73 additions & 0 deletions arch/blackfin/kernel/pseudodbg.c
Original file line number Diff line number Diff line change
@@ -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;
}
15 changes: 15 additions & 0 deletions arch/blackfin/kernel/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 6ce3e9c

Please sign in to comment.