]>
Commit | Line | Data |
---|---|---|
9438fe7d MC |
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" | |
9438fe7d | 20 | #include "exec/gdbstub.h" |
4ea5fe99 | 21 | #include "gdbstub/helpers.h" |
9438fe7d MC |
22 | #include "cpu.h" |
23 | ||
719d3561 HW |
24 | struct TypeSize { |
25 | const char *gdb_type; | |
26 | const char *id; | |
27 | int size; | |
28 | const char suffix; | |
29 | }; | |
30 | ||
31 | static const struct TypeSize vec_lanes[] = { | |
32 | /* quads */ | |
33 | { "uint128", "quads", 128, 'q' }, | |
34 | /* 64 bit */ | |
35 | { "uint64", "longs", 64, 'l' }, | |
36 | /* 32 bit */ | |
37 | { "uint32", "words", 32, 'w' }, | |
38 | /* 16 bit */ | |
39 | { "uint16", "shorts", 16, 's' }, | |
40 | /* | |
41 | * TODO: currently there is no reliable way of telling | |
42 | * if the remote gdb actually understands ieee_half so | |
43 | * we don't expose it in the target description for now. | |
44 | * { "ieee_half", 16, 'h', 'f' }, | |
45 | */ | |
46 | /* bytes */ | |
47 | { "uint8", "bytes", 8, 'b' }, | |
48 | }; | |
49 | ||
a010bdbe | 50 | int riscv_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) |
9438fe7d MC |
51 | { |
52 | RISCVCPU *cpu = RISCV_CPU(cs); | |
53 | CPURISCVState *env = &cpu->env; | |
1191be09 | 54 | target_ulong tmp; |
9438fe7d MC |
55 | |
56 | if (n < 32) { | |
1191be09 | 57 | tmp = env->gpr[n]; |
9438fe7d | 58 | } else if (n == 32) { |
1191be09 LZ |
59 | tmp = env->pc; |
60 | } else { | |
61 | return 0; | |
62 | } | |
63 | ||
64 | switch (env->misa_mxl_max) { | |
65 | case MXL_RV32: | |
66 | return gdb_get_reg32(mem_buf, tmp); | |
67 | case MXL_RV64: | |
6c3a9247 | 68 | case MXL_RV128: |
1191be09 LZ |
69 | return gdb_get_reg64(mem_buf, tmp); |
70 | default: | |
71 | g_assert_not_reached(); | |
9438fe7d MC |
72 | } |
73 | return 0; | |
74 | } | |
75 | ||
76 | int riscv_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) | |
77 | { | |
78 | RISCVCPU *cpu = RISCV_CPU(cs); | |
79 | CPURISCVState *env = &cpu->env; | |
1191be09 LZ |
80 | int length = 0; |
81 | target_ulong tmp; | |
82 | ||
83 | switch (env->misa_mxl_max) { | |
84 | case MXL_RV32: | |
85 | tmp = (int32_t)ldl_p(mem_buf); | |
86 | length = 4; | |
87 | break; | |
88 | case MXL_RV64: | |
6c3a9247 | 89 | case MXL_RV128: |
1191be09 LZ |
90 | if (env->xl < MXL_RV64) { |
91 | tmp = (int32_t)ldq_p(mem_buf); | |
92 | } else { | |
93 | tmp = ldq_p(mem_buf); | |
94 | } | |
95 | length = 8; | |
96 | break; | |
97 | default: | |
98 | g_assert_not_reached(); | |
99 | } | |
100 | if (n > 0 && n < 32) { | |
101 | env->gpr[n] = tmp; | |
9438fe7d | 102 | } else if (n == 32) { |
1191be09 | 103 | env->pc = tmp; |
5371f5cd | 104 | } |
1191be09 LZ |
105 | |
106 | return length; | |
5371f5cd JW |
107 | } |
108 | ||
a010bdbe | 109 | static int riscv_gdb_get_fpu(CPURISCVState *env, GByteArray *buf, int n) |
5371f5cd JW |
110 | { |
111 | if (n < 32) { | |
e91a7227 | 112 | if (env->misa_ext & RVD) { |
a010bdbe | 113 | return gdb_get_reg64(buf, env->fpr[n]); |
ae4a70c0 | 114 | } |
e91a7227 | 115 | if (env->misa_ext & RVF) { |
a010bdbe | 116 | return gdb_get_reg32(buf, env->fpr[n]); |
ae4a70c0 | 117 | } |
5371f5cd JW |
118 | } |
119 | return 0; | |
120 | } | |
121 | ||
122 | static int riscv_gdb_set_fpu(CPURISCVState *env, uint8_t *mem_buf, int n) | |
123 | { | |
124 | if (n < 32) { | |
125 | env->fpr[n] = ldq_p(mem_buf); /* always 64-bit */ | |
9438fe7d | 126 | return sizeof(uint64_t); |
9438fe7d MC |
127 | } |
128 | return 0; | |
129 | } | |
5371f5cd | 130 | |
719d3561 HW |
131 | static int riscv_gdb_get_vector(CPURISCVState *env, GByteArray *buf, int n) |
132 | { | |
133 | uint16_t vlenb = env_archcpu(env)->cfg.vlen >> 3; | |
134 | if (n < 32) { | |
135 | int i; | |
136 | int cnt = 0; | |
137 | for (i = 0; i < vlenb; i += 8) { | |
138 | cnt += gdb_get_reg64(buf, | |
139 | env->vreg[(n * vlenb + i) / 8]); | |
140 | } | |
141 | return cnt; | |
142 | } | |
143 | ||
719d3561 HW |
144 | return 0; |
145 | } | |
146 | ||
147 | static int riscv_gdb_set_vector(CPURISCVState *env, uint8_t *mem_buf, int n) | |
148 | { | |
149 | uint16_t vlenb = env_archcpu(env)->cfg.vlen >> 3; | |
150 | if (n < 32) { | |
151 | int i; | |
152 | for (i = 0; i < vlenb; i += 8) { | |
153 | env->vreg[(n * vlenb + i) / 8] = ldq_p(mem_buf + i); | |
154 | } | |
155 | return vlenb; | |
156 | } | |
157 | ||
719d3561 HW |
158 | return 0; |
159 | } | |
160 | ||
a010bdbe | 161 | static int riscv_gdb_get_csr(CPURISCVState *env, GByteArray *buf, int n) |
5371f5cd | 162 | { |
b93777e1 | 163 | if (n < CSR_TABLE_SIZE) { |
5371f5cd JW |
164 | target_ulong val = 0; |
165 | int result; | |
166 | ||
b93777e1 | 167 | result = riscv_csrrw_debug(env, n, &val, 0, 0); |
533c91e8 | 168 | if (result == RISCV_EXCP_NONE) { |
a010bdbe | 169 | return gdb_get_regl(buf, val); |
5371f5cd JW |
170 | } |
171 | } | |
172 | return 0; | |
173 | } | |
174 | ||
175 | static int riscv_gdb_set_csr(CPURISCVState *env, uint8_t *mem_buf, int n) | |
176 | { | |
b93777e1 | 177 | if (n < CSR_TABLE_SIZE) { |
5371f5cd JW |
178 | target_ulong val = ldtul_p(mem_buf); |
179 | int result; | |
180 | ||
b93777e1 | 181 | result = riscv_csrrw_debug(env, n, NULL, val, -1); |
533c91e8 | 182 | if (result == RISCV_EXCP_NONE) { |
5371f5cd JW |
183 | return sizeof(target_ulong); |
184 | } | |
185 | } | |
186 | return 0; | |
187 | } | |
188 | ||
a010bdbe | 189 | static int riscv_gdb_get_virtual(CPURISCVState *cs, GByteArray *buf, int n) |
ab9056ff JB |
190 | { |
191 | if (n == 0) { | |
192 | #ifdef CONFIG_USER_ONLY | |
a010bdbe | 193 | return gdb_get_regl(buf, 0); |
ab9056ff | 194 | #else |
a010bdbe | 195 | return gdb_get_regl(buf, cs->priv); |
ab9056ff JB |
196 | #endif |
197 | } | |
198 | return 0; | |
199 | } | |
200 | ||
201 | static int riscv_gdb_set_virtual(CPURISCVState *cs, uint8_t *mem_buf, int n) | |
202 | { | |
81d2929c JB |
203 | if (n == 0) { |
204 | #ifndef CONFIG_USER_ONLY | |
205 | cs->priv = ldtul_p(mem_buf) & 0x3; | |
206 | if (cs->priv == PRV_H) { | |
207 | cs->priv = PRV_S; | |
208 | } | |
209 | #endif | |
210 | return sizeof(target_ulong); | |
211 | } | |
ab9056ff JB |
212 | return 0; |
213 | } | |
214 | ||
b93777e1 BM |
215 | static int riscv_gen_dynamic_csr_xml(CPUState *cs, int base_reg) |
216 | { | |
217 | RISCVCPU *cpu = RISCV_CPU(cs); | |
218 | CPURISCVState *env = &cpu->env; | |
219 | GString *s = g_string_new(NULL); | |
220 | riscv_csr_predicate_fn predicate; | |
db23e5d9 | 221 | int bitsize = 16 << env->misa_mxl_max; |
b93777e1 BM |
222 | int i; |
223 | ||
a1f0083c BM |
224 | #if !defined(CONFIG_USER_ONLY) |
225 | env->debugger = true; | |
226 | #endif | |
227 | ||
332dab68 FP |
228 | /* Until gdb knows about 128-bit registers */ |
229 | if (bitsize > 64) { | |
230 | bitsize = 64; | |
231 | } | |
232 | ||
b93777e1 BM |
233 | g_string_printf(s, "<?xml version=\"1.0\"?>"); |
234 | g_string_append_printf(s, "<!DOCTYPE feature SYSTEM \"gdb-target.dtd\">"); | |
235 | g_string_append_printf(s, "<feature name=\"org.gnu.gdb.riscv.csr\">"); | |
236 | ||
237 | for (i = 0; i < CSR_TABLE_SIZE; i++) { | |
0bc71ee0 BM |
238 | if (env->priv_ver < csr_ops[i].min_priv_ver) { |
239 | continue; | |
240 | } | |
b93777e1 | 241 | predicate = csr_ops[i].predicate; |
79a41289 | 242 | if (predicate && (predicate(env, i) == RISCV_EXCP_NONE)) { |
b93777e1 BM |
243 | if (csr_ops[i].name) { |
244 | g_string_append_printf(s, "<reg name=\"%s\"", csr_ops[i].name); | |
245 | } else { | |
246 | g_string_append_printf(s, "<reg name=\"csr%03x\"", i); | |
247 | } | |
248 | g_string_append_printf(s, " bitsize=\"%d\"", bitsize); | |
249 | g_string_append_printf(s, " regnum=\"%d\"/>", base_reg + i); | |
250 | } | |
251 | } | |
252 | ||
253 | g_string_append_printf(s, "</feature>"); | |
254 | ||
255 | cpu->dyn_csr_xml = g_string_free(s, false); | |
a1f0083c BM |
256 | |
257 | #if !defined(CONFIG_USER_ONLY) | |
258 | env->debugger = false; | |
259 | #endif | |
260 | ||
b93777e1 BM |
261 | return CSR_TABLE_SIZE; |
262 | } | |
263 | ||
719d3561 HW |
264 | static int ricsv_gen_dynamic_vector_xml(CPUState *cs, int base_reg) |
265 | { | |
266 | RISCVCPU *cpu = RISCV_CPU(cs); | |
267 | GString *s = g_string_new(NULL); | |
268 | g_autoptr(GString) ts = g_string_new(""); | |
269 | int reg_width = cpu->cfg.vlen; | |
270 | int num_regs = 0; | |
271 | int i; | |
272 | ||
273 | g_string_printf(s, "<?xml version=\"1.0\"?>"); | |
274 | g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">"); | |
275 | g_string_append_printf(s, "<feature name=\"org.gnu.gdb.riscv.vector\">"); | |
276 | ||
277 | /* First define types and totals in a whole VL */ | |
278 | for (i = 0; i < ARRAY_SIZE(vec_lanes); i++) { | |
279 | int count = reg_width / vec_lanes[i].size; | |
280 | g_string_printf(ts, "%s", vec_lanes[i].id); | |
281 | g_string_append_printf(s, | |
282 | "<vector id=\"%s\" type=\"%s\" count=\"%d\"/>", | |
283 | ts->str, vec_lanes[i].gdb_type, count); | |
284 | } | |
285 | ||
286 | /* Define unions */ | |
287 | g_string_append_printf(s, "<union id=\"riscv_vector\">"); | |
288 | for (i = 0; i < ARRAY_SIZE(vec_lanes); i++) { | |
289 | g_string_append_printf(s, "<field name=\"%c\" type=\"%s\"/>", | |
290 | vec_lanes[i].suffix, | |
291 | vec_lanes[i].id); | |
292 | } | |
293 | g_string_append(s, "</union>"); | |
294 | ||
295 | /* Define vector registers */ | |
296 | for (i = 0; i < 32; i++) { | |
297 | g_string_append_printf(s, | |
298 | "<reg name=\"v%d\" bitsize=\"%d\"" | |
299 | " regnum=\"%d\" group=\"vector\"" | |
300 | " type=\"riscv_vector\"/>", | |
301 | i, reg_width, base_reg++); | |
302 | num_regs++; | |
303 | } | |
304 | ||
719d3561 HW |
305 | g_string_append_printf(s, "</feature>"); |
306 | ||
307 | cpu->dyn_vreg_xml = g_string_free(s, false); | |
308 | return num_regs; | |
309 | } | |
310 | ||
5371f5cd JW |
311 | void riscv_cpu_register_gdb_regs_for_features(CPUState *cs) |
312 | { | |
313 | RISCVCPU *cpu = RISCV_CPU(cs); | |
314 | CPURISCVState *env = &cpu->env; | |
e91a7227 | 315 | if (env->misa_ext & RVD) { |
ae4a70c0 | 316 | gdb_register_coprocessor(cs, riscv_gdb_get_fpu, riscv_gdb_set_fpu, |
94452ac4 | 317 | 32, "riscv-64bit-fpu.xml", 0); |
e91a7227 | 318 | } else if (env->misa_ext & RVF) { |
5371f5cd | 319 | gdb_register_coprocessor(cs, riscv_gdb_get_fpu, riscv_gdb_set_fpu, |
94452ac4 | 320 | 32, "riscv-32bit-fpu.xml", 0); |
5371f5cd | 321 | } |
719d3561 | 322 | if (env->misa_ext & RVV) { |
28eb8bee | 323 | int base_reg = cs->gdb_num_regs; |
719d3561 | 324 | gdb_register_coprocessor(cs, riscv_gdb_get_vector, riscv_gdb_set_vector, |
28eb8bee | 325 | ricsv_gen_dynamic_vector_xml(cs, base_reg), |
719d3561 HW |
326 | "riscv-vector.xml", 0); |
327 | } | |
1191be09 LZ |
328 | switch (env->misa_mxl_max) { |
329 | case MXL_RV32: | |
330 | gdb_register_coprocessor(cs, riscv_gdb_get_virtual, | |
331 | riscv_gdb_set_virtual, | |
332 | 1, "riscv-32bit-virtual.xml", 0); | |
333 | break; | |
334 | case MXL_RV64: | |
6c3a9247 | 335 | case MXL_RV128: |
1191be09 LZ |
336 | gdb_register_coprocessor(cs, riscv_gdb_get_virtual, |
337 | riscv_gdb_set_virtual, | |
338 | 1, "riscv-64bit-virtual.xml", 0); | |
339 | break; | |
340 | default: | |
341 | g_assert_not_reached(); | |
342 | } | |
b93777e1 | 343 | |
e17e2c7c BM |
344 | if (cpu->cfg.ext_icsr) { |
345 | int base_reg = cs->gdb_num_regs; | |
346 | gdb_register_coprocessor(cs, riscv_gdb_get_csr, riscv_gdb_set_csr, | |
347 | riscv_gen_dynamic_csr_xml(cs, base_reg), | |
348 | "riscv-csr.xml", 0); | |
349 | } | |
5371f5cd | 350 | } |