1a1d30cb0609c60cc3a92528060a10f1f4d286e4
[sfrench/cifs-2.6.git] / arch / h8300 / kernel / kgdb.c
1 /*
2  * H8/300 KGDB support
3  *
4  * Copyright (C) 2015 Yoshinori Sato <ysato@users.sourceforge.jp>
5  *
6  * This file is subject to the terms and conditions of the GNU General Public
7  * License.  See the file "COPYING" in the main directory of this archive
8  * for more details.
9  */
10
11 #include <linux/ptrace.h>
12 #include <linux/kgdb.h>
13 #include <linux/kdebug.h>
14 #include <linux/io.h>
15
16 struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = {
17         { "er0", GDB_SIZEOF_REG, offsetof(struct pt_regs, er0) },
18         { "er1", GDB_SIZEOF_REG, offsetof(struct pt_regs, er1) },
19         { "er2", GDB_SIZEOF_REG, offsetof(struct pt_regs, er2) },
20         { "er3", GDB_SIZEOF_REG, offsetof(struct pt_regs, er3) },
21         { "er4", GDB_SIZEOF_REG, offsetof(struct pt_regs, er4) },
22         { "er5", GDB_SIZEOF_REG, offsetof(struct pt_regs, er5) },
23         { "er6", GDB_SIZEOF_REG, offsetof(struct pt_regs, er6) },
24         { "sp", GDB_SIZEOF_REG, offsetof(struct pt_regs, sp) },
25         { "ccr", GDB_SIZEOF_REG, offsetof(struct pt_regs, ccr) },
26         { "pc", GDB_SIZEOF_REG, offsetof(struct pt_regs, pc) },
27         { "cycles", GDB_SIZEOF_REG, -1 },
28 #if defined(CONFIG_CPU_H8S)
29         { "exr", GDB_SIZEOF_REG, offsetof(struct pt_regs, exr) },
30 #endif
31         { "tick", GDB_SIZEOF_REG, -1 },
32         { "inst", GDB_SIZEOF_REG, -1 },
33 };
34
35 char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs)
36 {
37         if (regno >= DBG_MAX_REG_NUM || regno < 0)
38                 return NULL;
39
40         switch (regno) {
41         case GDB_CCR:
42 #if defined(CONFIG_CPU_H8S)
43         case GDB_EXR:
44 #endif
45                 *(u32 *)mem = *(u16 *)((void *)regs +
46                                        dbg_reg_def[regno].offset);
47                 break;
48         default:
49                 if (dbg_reg_def[regno].offset >= 0)
50                         memcpy(mem, (void *)regs + dbg_reg_def[regno].offset,
51                                dbg_reg_def[regno].size);
52                 else
53                         memset(mem, 0, dbg_reg_def[regno].size);
54                 break;
55         }
56         return dbg_reg_def[regno].name;
57 }
58
59 int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
60 {
61         if (regno >= DBG_MAX_REG_NUM || regno < 0)
62                 return -EINVAL;
63
64         switch (regno) {
65         case GDB_CCR:
66 #if defined(CONFIG_CPU_H8S)
67         case GDB_EXR:
68 #endif
69                 *(u16 *)((void *)regs +
70                          dbg_reg_def[regno].offset) = *(u32 *)mem;
71                 break;
72         default:
73                 memcpy((void *)regs + dbg_reg_def[regno].offset, mem,
74                        dbg_reg_def[regno].size);
75         }
76         return 0;
77 }
78
79 asmlinkage void h8300_kgdb_trap(struct pt_regs *regs)
80 {
81         regs->pc &= 0x00ffffff;
82         if (kgdb_handle_exception(10, SIGTRAP, 0, regs))
83                 return;
84         if (*(u16 *)(regs->pc) == *(u16 *)&arch_kgdb_ops.gdb_bpt_instr)
85                 regs->pc += BREAK_INSTR_SIZE;
86         regs->pc |= regs->ccr << 24;
87 }
88
89 void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
90 {
91         memset((char *)gdb_regs, 0, NUMREGBYTES);
92         gdb_regs[GDB_SP] = p->thread.ksp;
93         gdb_regs[GDB_PC] = KSTK_EIP(p);
94 }
95
96 void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc)
97 {
98         regs->pc = pc;
99 }
100
101 int kgdb_arch_handle_exception(int vector, int signo, int err_code,
102                                 char *remcom_in_buffer, char *remcom_out_buffer,
103                                 struct pt_regs *regs)
104 {
105         char *ptr;
106         unsigned long addr;
107
108         switch (remcom_in_buffer[0]) {
109         case 's':
110         case 'c':
111                 /* handle the optional parameters */
112                 ptr = &remcom_in_buffer[1];
113                 if (kgdb_hex2long(&ptr, &addr))
114                         regs->pc = addr;
115
116                 return 0;
117         }
118
119         return -1; /* this means that we do not want to exit from the handler */
120 }
121
122 int kgdb_arch_init(void)
123 {
124         return 0;
125 }
126
127 void kgdb_arch_exit(void)
128 {
129         /* Nothing to do */
130 }
131
132 struct kgdb_arch arch_kgdb_ops = {
133         /* Breakpoint instruction: trapa #2 */
134         .gdb_bpt_instr = { 0x57, 0x20 },
135 };