summaryrefslogtreecommitdiff
path: root/arch/blackfin/kernel/pseudodbg.c
blob: a5a4636124aa0c8ef8bb35e14c3944690487b4c3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/* 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>

/*
 * 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.
 */
static bool fix_up_reg(struct pt_regs *fp, long *value, int grp, int reg)
{
	long *val = &fp->r0;

	/* Only do Dregs and Pregs for now */
	if (grp > 1)
		return false;

	if (grp == 0 || (grp == 1 && reg < 6))
		val -= (reg + 8 * grp);
	else if (grp == 1 && reg == 6)
		val = &fp->usp;
	else if (grp == 1 && reg == 7)
		val = &fp->fp;

	*value = *val;
	return true;

}

#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

/*
 * DBGA - debug assert
 */
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;

	if ((opcode & 0xFF000000) != PseudoDbg_Assert_opcode)
		return false;

	if (!fix_up_reg(fp, &value, grp, regtest))
		return false;

	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;
}

#define PseudoDbg_opcode        0xf8000000
#define PseudoDbg_reg_bits      0
#define PseudoDbg_reg_mask      0x7
#define PseudoDbg_grp_bits      3
#define PseudoDbg_grp_mask      0x7
#define PseudoDbg_fn_bits       6
#define PseudoDbg_fn_mask       0x3
#define PseudoDbg_code_bits     8
#define PseudoDbg_code_mask     0xff

/*
 * DBG - debug (dump a register value out)
 */
bool execute_pseudodbg(struct pt_regs *fp, unsigned int opcode)
{
	int grp, fn, reg;
	long value;

	if ((opcode & 0xFF000000) != PseudoDbg_opcode)
		return false;

	opcode >>= 16;
	grp = ((opcode >> PseudoDbg_grp_bits) & PseudoDbg_reg_mask);
	fn  = ((opcode >> PseudoDbg_fn_bits)  & PseudoDbg_fn_mask);
	reg = ((opcode >> PseudoDbg_reg_bits) & PseudoDbg_reg_mask);

	if (!fix_up_reg(fp, &value, grp, reg))
		return false;

	pr_notice("DBG %s%d = %08lx\n", grp ? "P" : "R", reg, value);

	fp->pc += 2;
	return true;
}