xref: /openbmc/qemu/target/riscv/gdbstub.c (revision 278f064e)
1 /*
2  * RISC-V GDB Server Stub
3  *
4  * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2 or later, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "qemu/osdep.h"
20 #include "exec/gdbstub.h"
21 #include "cpu.h"
22 
23 int riscv_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
24 {
25     RISCVCPU *cpu = RISCV_CPU(cs);
26     CPURISCVState *env = &cpu->env;
27 
28     if (n < 32) {
29         return gdb_get_regl(mem_buf, env->gpr[n]);
30     } else if (n == 32) {
31         return gdb_get_regl(mem_buf, env->pc);
32     }
33     return 0;
34 }
35 
36 int riscv_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
37 {
38     RISCVCPU *cpu = RISCV_CPU(cs);
39     CPURISCVState *env = &cpu->env;
40 
41     if (n == 0) {
42         /* discard writes to x0 */
43         return sizeof(target_ulong);
44     } else if (n < 32) {
45         env->gpr[n] = ldtul_p(mem_buf);
46         return sizeof(target_ulong);
47     } else if (n == 32) {
48         env->pc = ldtul_p(mem_buf);
49         return sizeof(target_ulong);
50     }
51     return 0;
52 }
53 
54 static int riscv_gdb_get_fpu(CPURISCVState *env, GByteArray *buf, int n)
55 {
56     if (n < 32) {
57         if (env->misa & RVD) {
58             return gdb_get_reg64(buf, env->fpr[n]);
59         }
60         if (env->misa & RVF) {
61             return gdb_get_reg32(buf, env->fpr[n]);
62         }
63     /* there is hole between ft11 and fflags in fpu.xml */
64     } else if (n < 36 && n > 32) {
65         target_ulong val = 0;
66         int result;
67         /*
68          * CSR_FFLAGS is at index 1 in csr_register, and gdb says it is FP
69          * register 33, so we recalculate the map index.
70          * This also works for CSR_FRM and CSR_FCSR.
71          */
72         result = riscv_csrrw_debug(env, n - 32, &val,
73                                    0, 0);
74         if (result == RISCV_EXCP_NONE) {
75             return gdb_get_regl(buf, val);
76         }
77     }
78     return 0;
79 }
80 
81 static int riscv_gdb_set_fpu(CPURISCVState *env, uint8_t *mem_buf, int n)
82 {
83     if (n < 32) {
84         env->fpr[n] = ldq_p(mem_buf); /* always 64-bit */
85         return sizeof(uint64_t);
86     /* there is hole between ft11 and fflags in fpu.xml */
87     } else if (n < 36 && n > 32) {
88         target_ulong val = ldtul_p(mem_buf);
89         int result;
90         /*
91          * CSR_FFLAGS is at index 1 in csr_register, and gdb says it is FP
92          * register 33, so we recalculate the map index.
93          * This also works for CSR_FRM and CSR_FCSR.
94          */
95         result = riscv_csrrw_debug(env, n - 32, NULL,
96                                    val, -1);
97         if (result == RISCV_EXCP_NONE) {
98             return sizeof(target_ulong);
99         }
100     }
101     return 0;
102 }
103 
104 static int riscv_gdb_get_csr(CPURISCVState *env, GByteArray *buf, int n)
105 {
106     if (n < CSR_TABLE_SIZE) {
107         target_ulong val = 0;
108         int result;
109 
110         result = riscv_csrrw_debug(env, n, &val, 0, 0);
111         if (result == RISCV_EXCP_NONE) {
112             return gdb_get_regl(buf, val);
113         }
114     }
115     return 0;
116 }
117 
118 static int riscv_gdb_set_csr(CPURISCVState *env, uint8_t *mem_buf, int n)
119 {
120     if (n < CSR_TABLE_SIZE) {
121         target_ulong val = ldtul_p(mem_buf);
122         int result;
123 
124         result = riscv_csrrw_debug(env, n, NULL, val, -1);
125         if (result == RISCV_EXCP_NONE) {
126             return sizeof(target_ulong);
127         }
128     }
129     return 0;
130 }
131 
132 static int riscv_gdb_get_virtual(CPURISCVState *cs, GByteArray *buf, int n)
133 {
134     if (n == 0) {
135 #ifdef CONFIG_USER_ONLY
136         return gdb_get_regl(buf, 0);
137 #else
138         return gdb_get_regl(buf, cs->priv);
139 #endif
140     }
141     return 0;
142 }
143 
144 static int riscv_gdb_set_virtual(CPURISCVState *cs, uint8_t *mem_buf, int n)
145 {
146     if (n == 0) {
147 #ifndef CONFIG_USER_ONLY
148         cs->priv = ldtul_p(mem_buf) & 0x3;
149         if (cs->priv == PRV_H) {
150             cs->priv = PRV_S;
151         }
152 #endif
153         return sizeof(target_ulong);
154     }
155     return 0;
156 }
157 
158 static int riscv_gen_dynamic_csr_xml(CPUState *cs, int base_reg)
159 {
160     RISCVCPU *cpu = RISCV_CPU(cs);
161     CPURISCVState *env = &cpu->env;
162     GString *s = g_string_new(NULL);
163     riscv_csr_predicate_fn predicate;
164     int bitsize = riscv_cpu_is_32bit(env) ? 32 : 64;
165     int i;
166 
167     g_string_printf(s, "<?xml version=\"1.0\"?>");
168     g_string_append_printf(s, "<!DOCTYPE feature SYSTEM \"gdb-target.dtd\">");
169     g_string_append_printf(s, "<feature name=\"org.gnu.gdb.riscv.csr\">");
170 
171     for (i = 0; i < CSR_TABLE_SIZE; i++) {
172         predicate = csr_ops[i].predicate;
173         if (predicate && !predicate(env, i)) {
174             if (csr_ops[i].name) {
175                 g_string_append_printf(s, "<reg name=\"%s\"", csr_ops[i].name);
176             } else {
177                 g_string_append_printf(s, "<reg name=\"csr%03x\"", i);
178             }
179             g_string_append_printf(s, " bitsize=\"%d\"", bitsize);
180             g_string_append_printf(s, " regnum=\"%d\"/>", base_reg + i);
181         }
182     }
183 
184     g_string_append_printf(s, "</feature>");
185 
186     cpu->dyn_csr_xml = g_string_free(s, false);
187     return CSR_TABLE_SIZE;
188 }
189 
190 void riscv_cpu_register_gdb_regs_for_features(CPUState *cs)
191 {
192     RISCVCPU *cpu = RISCV_CPU(cs);
193     CPURISCVState *env = &cpu->env;
194     if (env->misa & RVD) {
195         gdb_register_coprocessor(cs, riscv_gdb_get_fpu, riscv_gdb_set_fpu,
196                                  36, "riscv-64bit-fpu.xml", 0);
197     } else if (env->misa & RVF) {
198         gdb_register_coprocessor(cs, riscv_gdb_get_fpu, riscv_gdb_set_fpu,
199                                  36, "riscv-32bit-fpu.xml", 0);
200     }
201 #if defined(TARGET_RISCV32)
202     gdb_register_coprocessor(cs, riscv_gdb_get_virtual, riscv_gdb_set_virtual,
203                              1, "riscv-32bit-virtual.xml", 0);
204 #elif defined(TARGET_RISCV64)
205     gdb_register_coprocessor(cs, riscv_gdb_get_virtual, riscv_gdb_set_virtual,
206                              1, "riscv-64bit-virtual.xml", 0);
207 #endif
208 
209     gdb_register_coprocessor(cs, riscv_gdb_get_csr, riscv_gdb_set_csr,
210                              riscv_gen_dynamic_csr_xml(cs, cs->gdb_num_regs),
211                              "riscv-csr.xml", 0);
212 }
213