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