16ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz/* The fake debug assert instructions
26ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz *
36ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz * Copyright 2010 Analog Devices Inc.
46ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz *
56ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz * Licensed under the GPL-2 or later
66ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz */
76ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz
86ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz#include <linux/types.h>
96ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz#include <linux/kernel.h>
106ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz#include <linux/ptrace.h>
116ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz
125a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getzconst char * const greg_names[] = {
135a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz	"R0",    "R1",      "R2",     "R3",    "R4",    "R5",    "R6",     "R7",
145a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz	"P0",    "P1",      "P2",     "P3",    "P4",    "P5",    "SP",     "FP",
155a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz	"I0",    "I1",      "I2",     "I3",    "M0",    "M1",    "M2",     "M3",
165a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz	"B0",    "B1",      "B2",     "B3",    "L0",    "L1",    "L2",     "L3",
175a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz	"A0.X",  "A0.W",    "A1.X",   "A1.W",  "<res>", "<res>", "ASTAT",  "RETS",
185a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz	"<res>", "<res>",   "<res>",  "<res>", "<res>", "<res>", "<res>",  "<res>",
195a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz	"LC0",   "LT0",     "LB0",    "LC1",   "LT1",   "LB1",   "CYCLES", "CYCLES2",
205a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz	"USP",   "SEQSTAT", "SYSCFG", "RETI",  "RETX",  "RETN",  "RETE",   "EMUDAT",
215a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz};
225a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz
235a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getzstatic const char *get_allreg_name(int grp, int reg)
245a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz{
255a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz	return greg_names[(grp << 3) | reg];
265a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz}
275a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz
28dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz/*
29dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz * Unfortunately, the pt_regs structure is not laid out the same way as the
30dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz * hardware register file, so we need to do some fix ups.
315a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz *
325a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz * CYCLES is not stored in the pt_regs structure - so, we just read it from
335a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz * the hardware.
345a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz *
355a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz * Don't support:
365a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz *  - All reserved registers
375a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz *  - All in group 7 are (supervisors only)
38dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz */
395a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz
40dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getzstatic bool fix_up_reg(struct pt_regs *fp, long *value, int grp, int reg)
41dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz{
42dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz	long *val = &fp->r0;
435a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz	unsigned long tmp;
44dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz
45dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz	/* Only do Dregs and Pregs for now */
465a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz	if (grp == 5 ||
475a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz	   (grp == 4 && (reg == 4 || reg == 5)) ||
485a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz	   (grp == 7))
49dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz		return false;
50dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz
51dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz	if (grp == 0 || (grp == 1 && reg < 6))
52dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz		val -= (reg + 8 * grp);
53dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz	else if (grp == 1 && reg == 6)
54dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz		val = &fp->usp;
55dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz	else if (grp == 1 && reg == 7)
56dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz		val = &fp->fp;
575a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz	else if (grp == 2) {
585a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz		val = &fp->i0;
595a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz		val -= reg;
605a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz	} else if (grp == 3 && reg >= 4) {
615a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz		val = &fp->l0;
625a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz		val -= (reg - 4);
635a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz	} else if (grp == 3 && reg < 4) {
645a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz		val = &fp->b0;
655a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz		val -= reg;
665a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz	} else if (grp == 4 && reg < 4) {
675a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz		val = &fp->a0x;
685a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz		val -= reg;
695a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz	} else if (grp == 4 && reg == 6)
705a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz		val = &fp->astat;
715a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz	else if (grp == 4 && reg == 7)
725a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz		val = &fp->rets;
735a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz	else if (grp == 6 && reg < 6) {
745a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz		val = &fp->lc0;
755a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz		val -= reg;
765a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz	} else if (grp == 6 && reg == 6) {
775a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz		__asm__ __volatile__("%0 = cycles;\n" : "=d"(tmp));
785a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz		val = &tmp;
795a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz	} else if (grp == 6 && reg == 7) {
805a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz		__asm__ __volatile__("%0 = cycles2;\n" : "=d"(tmp));
815a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz		val = &tmp;
825a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz	}
83dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz
84dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz	*value = *val;
85dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz	return true;
86dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz
87dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz}
88dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz
896ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz#define PseudoDbg_Assert_opcode         0xf0000000
906ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz#define PseudoDbg_Assert_expected_bits  0
916ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz#define PseudoDbg_Assert_expected_mask  0xffff
926ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz#define PseudoDbg_Assert_regtest_bits   16
936ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz#define PseudoDbg_Assert_regtest_mask   0x7
946ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz#define PseudoDbg_Assert_grp_bits       19
956ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz#define PseudoDbg_Assert_grp_mask       0x7
966ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz#define PseudoDbg_Assert_dbgop_bits     22
976ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz#define PseudoDbg_Assert_dbgop_mask     0x3
986ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz#define PseudoDbg_Assert_dontcare_bits  24
996ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz#define PseudoDbg_Assert_dontcare_mask  0x7
1006ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz#define PseudoDbg_Assert_code_bits      27
1016ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz#define PseudoDbg_Assert_code_mask      0x1f
1026ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz
103dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz/*
104dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz * DBGA - debug assert
105dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz */
1066ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getzbool execute_pseudodbg_assert(struct pt_regs *fp, unsigned int opcode)
1076ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz{
1086ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz	int expected = ((opcode >> PseudoDbg_Assert_expected_bits) & PseudoDbg_Assert_expected_mask);
1096ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz	int dbgop    = ((opcode >> (PseudoDbg_Assert_dbgop_bits)) & PseudoDbg_Assert_dbgop_mask);
1106ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz	int grp      = ((opcode >> (PseudoDbg_Assert_grp_bits)) & PseudoDbg_Assert_grp_mask);
1116ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz	int regtest  = ((opcode >> (PseudoDbg_Assert_regtest_bits)) & PseudoDbg_Assert_regtest_mask);
112dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz	long value;
1136ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz
1146ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz	if ((opcode & 0xFF000000) != PseudoDbg_Assert_opcode)
1156ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz		return false;
1166ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz
117dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz	if (!fix_up_reg(fp, &value, grp, regtest))
1186ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz		return false;
1196ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz
1206ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz	if (dbgop == 0 || dbgop == 2) {
1216ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz		/* DBGA ( regs_lo , uimm16 ) */
1226ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz		/* DBGAL ( regs , uimm16 ) */
123dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz		if (expected != (value & 0xFFFF)) {
1245a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz			pr_notice("DBGA (%s.L,0x%x) failure, got 0x%x\n",
1255a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz				get_allreg_name(grp, regtest),
1265a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz				expected, (unsigned int)(value & 0xFFFF));
1276ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz			return false;
1286ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz		}
1296ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz
1306ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz	} else if (dbgop == 1 || dbgop == 3) {
1316ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz		/* DBGA ( regs_hi , uimm16 ) */
1326ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz		/* DBGAH ( regs , uimm16 ) */
133dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz		if (expected != ((value >> 16) & 0xFFFF)) {
1345a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz			pr_notice("DBGA (%s.H,0x%x) failure, got 0x%x\n",
1355a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz				get_allreg_name(grp, regtest),
1365a132f7aeba772e1e1f9ccbad14a6779cd40cdfbRobin Getz				expected, (unsigned int)((value >> 16) & 0xFFFF));
1376ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz			return false;
1386ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz		}
1396ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz	}
1406ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz
1416ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz	fp->pc += 4;
1426ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz	return true;
1436ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13fRobin Getz}
144dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz
145dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz#define PseudoDbg_opcode        0xf8000000
146dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz#define PseudoDbg_reg_bits      0
147dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz#define PseudoDbg_reg_mask      0x7
148dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz#define PseudoDbg_grp_bits      3
149dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz#define PseudoDbg_grp_mask      0x7
150dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz#define PseudoDbg_fn_bits       6
151dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz#define PseudoDbg_fn_mask       0x3
152dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz#define PseudoDbg_code_bits     8
153dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz#define PseudoDbg_code_mask     0xff
154dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz
155dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz/*
156dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz * DBG - debug (dump a register value out)
157dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz */
158dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getzbool execute_pseudodbg(struct pt_regs *fp, unsigned int opcode)
159dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz{
160dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz	int grp, fn, reg;
161a6d9dbf5e4daaf21b33917a809a5ac1e7bce9e05Robin Getz	long value, value1;
162dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz
163dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz	if ((opcode & 0xFF000000) != PseudoDbg_opcode)
164dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz		return false;
165dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz
166dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz	opcode >>= 16;
167dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz	grp = ((opcode >> PseudoDbg_grp_bits) & PseudoDbg_reg_mask);
168dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz	fn  = ((opcode >> PseudoDbg_fn_bits)  & PseudoDbg_fn_mask);
169dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz	reg = ((opcode >> PseudoDbg_reg_bits) & PseudoDbg_reg_mask);
170dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz
171a6d9dbf5e4daaf21b33917a809a5ac1e7bce9e05Robin Getz	if (fn == 3 && (reg == 0 || reg == 1)) {
172a6d9dbf5e4daaf21b33917a809a5ac1e7bce9e05Robin Getz		if (!fix_up_reg(fp, &value, 4, 2 * reg))
173a6d9dbf5e4daaf21b33917a809a5ac1e7bce9e05Robin Getz			return false;
174a6d9dbf5e4daaf21b33917a809a5ac1e7bce9e05Robin Getz		if (!fix_up_reg(fp, &value1, 4, 2 * reg + 1))
175a6d9dbf5e4daaf21b33917a809a5ac1e7bce9e05Robin Getz			return false;
176dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz
177a6d9dbf5e4daaf21b33917a809a5ac1e7bce9e05Robin Getz		pr_notice("DBG A%i = %02lx%08lx\n", reg, value & 0xFF, value1);
178a6d9dbf5e4daaf21b33917a809a5ac1e7bce9e05Robin Getz		fp->pc += 2;
179a6d9dbf5e4daaf21b33917a809a5ac1e7bce9e05Robin Getz		return true;
180dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz
181a6d9dbf5e4daaf21b33917a809a5ac1e7bce9e05Robin Getz	} else if (fn == 0) {
182a6d9dbf5e4daaf21b33917a809a5ac1e7bce9e05Robin Getz		if (!fix_up_reg(fp, &value, grp, reg))
183a6d9dbf5e4daaf21b33917a809a5ac1e7bce9e05Robin Getz			return false;
184a6d9dbf5e4daaf21b33917a809a5ac1e7bce9e05Robin Getz
185a6d9dbf5e4daaf21b33917a809a5ac1e7bce9e05Robin Getz		pr_notice("DBG %s = %08lx\n", get_allreg_name(grp, reg), value);
186a6d9dbf5e4daaf21b33917a809a5ac1e7bce9e05Robin Getz		fp->pc += 2;
187a6d9dbf5e4daaf21b33917a809a5ac1e7bce9e05Robin Getz		return true;
188a6d9dbf5e4daaf21b33917a809a5ac1e7bce9e05Robin Getz	}
189a6d9dbf5e4daaf21b33917a809a5ac1e7bce9e05Robin Getz
190a6d9dbf5e4daaf21b33917a809a5ac1e7bce9e05Robin Getz	return false;
191dc89d97fc73176c883b32ff21ae6f1164ca20d05Robin Getz}
192