]>
Commit | Line | Data |
---|---|---|
96ff2d70 YS |
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 | const struct kgdb_arch arch_kgdb_ops = { | |
133 | /* Breakpoint instruction: trapa #2 */ | |
134 | .gdb_bpt_instr = { 0x57, 0x20 }, | |
135 | }; |