]>
Commit | Line | Data |
---|---|---|
58850dad AF |
1 | /* |
2 | * ARM gdb server stub | |
3 | * | |
4 | * Copyright (c) 2003-2005 Fabrice Bellard | |
5 | * Copyright (c) 2013 SUSE LINUX Products GmbH | |
6 | * | |
7 | * This library is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU Lesser General Public | |
9 | * License as published by the Free Software Foundation; either | |
50f57e09 | 10 | * version 2.1 of the License, or (at your option) any later version. |
58850dad AF |
11 | * |
12 | * This library is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * Lesser General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU Lesser General Public | |
18 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. | |
19 | */ | |
74c21bd0 | 20 | #include "qemu/osdep.h" |
33c11879 | 21 | #include "cpu.h" |
5b50e790 | 22 | #include "exec/gdbstub.h" |
4ea5fe99 | 23 | #include "gdbstub/helpers.h" |
46e3b237 | 24 | #include "sysemu/tcg.h" |
cf7c6d10 | 25 | #include "internals.h" |
5a534314 | 26 | #include "cpu-features.h" |
cf7c6d10 | 27 | #include "cpregs.h" |
58850dad | 28 | |
200bf5b7 AB |
29 | typedef struct RegisterSysregXmlParam { |
30 | CPUState *cs; | |
31 | GString *s; | |
32d6e32a | 32 | int n; |
200bf5b7 AB |
33 | } RegisterSysregXmlParam; |
34 | ||
58850dad AF |
35 | /* Old gdb always expect FPA registers. Newer (xml-aware) gdb only expect |
36 | whatever the target description contains. Due to a historical mishap | |
37 | the FPA registers appear in between core integer regs and the CPSR. | |
38 | We hack round this by giving the FPA regs zero size when talking to a | |
39 | newer gdb. */ | |
40 | ||
a010bdbe | 41 | int arm_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) |
58850dad | 42 | { |
5b50e790 AF |
43 | ARMCPU *cpu = ARM_CPU(cs); |
44 | CPUARMState *env = &cpu->env; | |
45 | ||
58850dad AF |
46 | if (n < 16) { |
47 | /* Core integer register. */ | |
986a2998 | 48 | return gdb_get_reg32(mem_buf, env->regs[n]); |
58850dad | 49 | } |
dd2f7e29 | 50 | if (n == 25) { |
c888f7e0 PM |
51 | /* CPSR, or XPSR for M-profile */ |
52 | if (arm_feature(env, ARM_FEATURE_M)) { | |
53 | return gdb_get_reg32(mem_buf, xpsr_read(env)); | |
54 | } else { | |
55 | return gdb_get_reg32(mem_buf, cpsr_read(env)); | |
56 | } | |
58850dad AF |
57 | } |
58 | /* Unknown register. */ | |
59 | return 0; | |
60 | } | |
61 | ||
5b50e790 | 62 | int arm_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) |
58850dad | 63 | { |
5b50e790 AF |
64 | ARMCPU *cpu = ARM_CPU(cs); |
65 | CPUARMState *env = &cpu->env; | |
58850dad AF |
66 | uint32_t tmp; |
67 | ||
68 | tmp = ldl_p(mem_buf); | |
69 | ||
7055fe4b RH |
70 | /* |
71 | * Mask out low bits of PC to workaround gdb bugs. | |
72 | * This avoids an assert in thumb_tr_translate_insn, because it is | |
73 | * architecturally impossible to misalign the pc. | |
74 | * This will probably cause problems if we ever implement the | |
75 | * Jazelle DBX extensions. | |
76 | */ | |
58850dad AF |
77 | if (n == 15) { |
78 | tmp &= ~1; | |
79 | } | |
80 | ||
81 | if (n < 16) { | |
82 | /* Core integer register. */ | |
888f470f PM |
83 | if (n == 13 && arm_feature(env, ARM_FEATURE_M)) { |
84 | /* M profile SP low bits are always 0 */ | |
85 | tmp &= ~3; | |
86 | } | |
58850dad AF |
87 | env->regs[n] = tmp; |
88 | return 4; | |
89 | } | |
dd2f7e29 | 90 | if (n == 25) { |
c888f7e0 PM |
91 | /* CPSR, or XPSR for M-profile */ |
92 | if (arm_feature(env, ARM_FEATURE_M)) { | |
93 | /* | |
94 | * Don't allow writing to XPSR.Exception as it can cause | |
95 | * a transition into or out of handler mode (it's not | |
9323e79f | 96 | * writable via the MSR insn so this is a reasonable |
c888f7e0 PM |
97 | * restriction). Other fields are safe to update. |
98 | */ | |
99 | xpsr_write(env, tmp, ~XPSR_EXCP); | |
100 | } else { | |
101 | cpsr_write(env, tmp, 0xffffffff, CPSRWriteByGDBStub); | |
102 | } | |
58850dad AF |
103 | return 4; |
104 | } | |
105 | /* Unknown register. */ | |
106 | return 0; | |
107 | } | |
200bf5b7 | 108 | |
89f4f20e PM |
109 | static int vfp_gdb_get_reg(CPUARMState *env, GByteArray *buf, int reg) |
110 | { | |
111 | ARMCPU *cpu = env_archcpu(env); | |
112 | int nregs = cpu_isar_feature(aa32_simd_r32, cpu) ? 32 : 16; | |
113 | ||
114 | /* VFP data registers are always little-endian. */ | |
115 | if (reg < nregs) { | |
116 | return gdb_get_reg64(buf, *aa32_vfp_dreg(env, reg)); | |
117 | } | |
118 | if (arm_feature(env, ARM_FEATURE_NEON)) { | |
119 | /* Aliases for Q regs. */ | |
120 | nregs += 16; | |
121 | if (reg < nregs) { | |
122 | uint64_t *q = aa32_vfp_qreg(env, reg - 32); | |
123 | return gdb_get_reg128(buf, q[0], q[1]); | |
124 | } | |
125 | } | |
126 | switch (reg - nregs) { | |
127 | case 0: | |
89f4f20e | 128 | return gdb_get_reg32(buf, vfp_get_fpscr(env)); |
89f4f20e PM |
129 | } |
130 | return 0; | |
131 | } | |
132 | ||
133 | static int vfp_gdb_set_reg(CPUARMState *env, uint8_t *buf, int reg) | |
134 | { | |
135 | ARMCPU *cpu = env_archcpu(env); | |
136 | int nregs = cpu_isar_feature(aa32_simd_r32, cpu) ? 32 : 16; | |
137 | ||
138 | if (reg < nregs) { | |
139 | *aa32_vfp_dreg(env, reg) = ldq_le_p(buf); | |
140 | return 8; | |
141 | } | |
142 | if (arm_feature(env, ARM_FEATURE_NEON)) { | |
143 | nregs += 16; | |
144 | if (reg < nregs) { | |
145 | uint64_t *q = aa32_vfp_qreg(env, reg - 32); | |
146 | q[0] = ldq_le_p(buf); | |
147 | q[1] = ldq_le_p(buf + 8); | |
148 | return 16; | |
149 | } | |
150 | } | |
151 | switch (reg - nregs) { | |
152 | case 0: | |
b355f08a | 153 | vfp_set_fpscr(env, ldl_p(buf)); |
89f4f20e | 154 | return 4; |
b355f08a PM |
155 | } |
156 | return 0; | |
157 | } | |
158 | ||
159 | static int vfp_gdb_get_sysreg(CPUARMState *env, GByteArray *buf, int reg) | |
160 | { | |
161 | switch (reg) { | |
162 | case 0: | |
163 | return gdb_get_reg32(buf, env->vfp.xregs[ARM_VFP_FPSID]); | |
89f4f20e | 164 | case 1: |
b355f08a PM |
165 | return gdb_get_reg32(buf, env->vfp.xregs[ARM_VFP_FPEXC]); |
166 | } | |
167 | return 0; | |
168 | } | |
169 | ||
170 | static int vfp_gdb_set_sysreg(CPUARMState *env, uint8_t *buf, int reg) | |
171 | { | |
172 | switch (reg) { | |
173 | case 0: | |
174 | env->vfp.xregs[ARM_VFP_FPSID] = ldl_p(buf); | |
89f4f20e | 175 | return 4; |
b355f08a | 176 | case 1: |
89f4f20e PM |
177 | env->vfp.xregs[ARM_VFP_FPEXC] = ldl_p(buf) & (1 << 30); |
178 | return 4; | |
179 | } | |
180 | return 0; | |
181 | } | |
182 | ||
dbd9e084 PM |
183 | static int mve_gdb_get_reg(CPUARMState *env, GByteArray *buf, int reg) |
184 | { | |
185 | switch (reg) { | |
186 | case 0: | |
187 | return gdb_get_reg32(buf, env->v7m.vpr); | |
188 | default: | |
189 | return 0; | |
190 | } | |
191 | } | |
192 | ||
193 | static int mve_gdb_set_reg(CPUARMState *env, uint8_t *buf, int reg) | |
194 | { | |
195 | switch (reg) { | |
196 | case 0: | |
197 | env->v7m.vpr = ldl_p(buf); | |
198 | return 4; | |
199 | default: | |
200 | return 0; | |
201 | } | |
202 | } | |
203 | ||
89f4f20e PM |
204 | /** |
205 | * arm_get/set_gdb_*: get/set a gdb register | |
206 | * @env: the CPU state | |
207 | * @buf: a buffer to copy to/from | |
208 | * @reg: register number (offset from start of group) | |
209 | * | |
210 | * We return the number of bytes copied | |
211 | */ | |
212 | ||
213 | static int arm_gdb_get_sysreg(CPUARMState *env, GByteArray *buf, int reg) | |
214 | { | |
215 | ARMCPU *cpu = env_archcpu(env); | |
216 | const ARMCPRegInfo *ri; | |
217 | uint32_t key; | |
218 | ||
219 | key = cpu->dyn_sysreg_xml.data.cpregs.keys[reg]; | |
220 | ri = get_arm_cp_reginfo(cpu->cp_regs, key); | |
221 | if (ri) { | |
222 | if (cpreg_field_is_64bit(ri)) { | |
223 | return gdb_get_reg64(buf, (uint64_t)read_raw_cp_reg(env, ri)); | |
224 | } else { | |
225 | return gdb_get_reg32(buf, (uint32_t)read_raw_cp_reg(env, ri)); | |
226 | } | |
227 | } | |
228 | return 0; | |
229 | } | |
230 | ||
231 | static int arm_gdb_set_sysreg(CPUARMState *env, uint8_t *buf, int reg) | |
232 | { | |
233 | return 0; | |
234 | } | |
235 | ||
448d4d14 AB |
236 | static void arm_gen_one_xml_sysreg_tag(GString *s, DynamicGDBXMLInfo *dyn_xml, |
237 | ARMCPRegInfo *ri, uint32_t ri_key, | |
32d6e32a | 238 | int bitsize, int regnum) |
200bf5b7 AB |
239 | { |
240 | g_string_append_printf(s, "<reg name=\"%s\"", ri->name); | |
241 | g_string_append_printf(s, " bitsize=\"%d\"", bitsize); | |
32d6e32a | 242 | g_string_append_printf(s, " regnum=\"%d\"", regnum); |
200bf5b7 | 243 | g_string_append_printf(s, " group=\"cp_regs\"/>"); |
448d4d14 AB |
244 | dyn_xml->data.cpregs.keys[dyn_xml->num] = ri_key; |
245 | dyn_xml->num++; | |
200bf5b7 AB |
246 | } |
247 | ||
248 | static void arm_register_sysreg_for_xml(gpointer key, gpointer value, | |
249 | gpointer p) | |
250 | { | |
5860362d | 251 | uint32_t ri_key = (uintptr_t)key; |
200bf5b7 AB |
252 | ARMCPRegInfo *ri = value; |
253 | RegisterSysregXmlParam *param = (RegisterSysregXmlParam *)p; | |
254 | GString *s = param->s; | |
255 | ARMCPU *cpu = ARM_CPU(param->cs); | |
256 | CPUARMState *env = &cpu->env; | |
448d4d14 | 257 | DynamicGDBXMLInfo *dyn_xml = &cpu->dyn_sysreg_xml; |
200bf5b7 AB |
258 | |
259 | if (!(ri->type & (ARM_CP_NO_RAW | ARM_CP_NO_GDB))) { | |
260 | if (arm_feature(env, ARM_FEATURE_AARCH64)) { | |
261 | if (ri->state == ARM_CP_STATE_AA64) { | |
32d6e32a AB |
262 | arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 64, |
263 | param->n++); | |
200bf5b7 AB |
264 | } |
265 | } else { | |
266 | if (ri->state == ARM_CP_STATE_AA32) { | |
267 | if (!arm_feature(env, ARM_FEATURE_EL3) && | |
268 | (ri->secure & ARM_CP_SECSTATE_S)) { | |
269 | return; | |
270 | } | |
271 | if (ri->type & ARM_CP_64BIT) { | |
32d6e32a AB |
272 | arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 64, |
273 | param->n++); | |
200bf5b7 | 274 | } else { |
32d6e32a AB |
275 | arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 32, |
276 | param->n++); | |
200bf5b7 AB |
277 | } |
278 | } | |
279 | } | |
280 | } | |
281 | } | |
282 | ||
4bce95b4 | 283 | static int arm_gen_dynamic_sysreg_xml(CPUState *cs, int base_reg) |
200bf5b7 AB |
284 | { |
285 | ARMCPU *cpu = ARM_CPU(cs); | |
286 | GString *s = g_string_new(NULL); | |
32d6e32a | 287 | RegisterSysregXmlParam param = {cs, s, base_reg}; |
200bf5b7 | 288 | |
448d4d14 AB |
289 | cpu->dyn_sysreg_xml.num = 0; |
290 | cpu->dyn_sysreg_xml.data.cpregs.keys = g_new(uint32_t, g_hash_table_size(cpu->cp_regs)); | |
200bf5b7 AB |
291 | g_string_printf(s, "<?xml version=\"1.0\"?>"); |
292 | g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">"); | |
293 | g_string_append_printf(s, "<feature name=\"org.qemu.gdb.arm.sys.regs\">"); | |
294 | g_hash_table_foreach(cpu->cp_regs, arm_register_sysreg_for_xml, ¶m); | |
295 | g_string_append_printf(s, "</feature>"); | |
448d4d14 AB |
296 | cpu->dyn_sysreg_xml.desc = g_string_free(s, false); |
297 | return cpu->dyn_sysreg_xml.num; | |
200bf5b7 AB |
298 | } |
299 | ||
893ca916 | 300 | #ifdef CONFIG_TCG |
7d8b28b8 RH |
301 | typedef enum { |
302 | M_SYSREG_MSP, | |
303 | M_SYSREG_PSP, | |
304 | M_SYSREG_PRIMASK, | |
305 | M_SYSREG_CONTROL, | |
306 | M_SYSREG_BASEPRI, | |
307 | M_SYSREG_FAULTMASK, | |
308 | M_SYSREG_MSPLIM, | |
309 | M_SYSREG_PSPLIM, | |
310 | } MProfileSysreg; | |
311 | ||
312 | static const struct { | |
313 | const char *name; | |
314 | int feature; | |
315 | } m_sysreg_def[] = { | |
316 | [M_SYSREG_MSP] = { "msp", ARM_FEATURE_M }, | |
317 | [M_SYSREG_PSP] = { "psp", ARM_FEATURE_M }, | |
318 | [M_SYSREG_PRIMASK] = { "primask", ARM_FEATURE_M }, | |
319 | [M_SYSREG_CONTROL] = { "control", ARM_FEATURE_M }, | |
320 | [M_SYSREG_BASEPRI] = { "basepri", ARM_FEATURE_M_MAIN }, | |
321 | [M_SYSREG_FAULTMASK] = { "faultmask", ARM_FEATURE_M_MAIN }, | |
322 | [M_SYSREG_MSPLIM] = { "msplim", ARM_FEATURE_V8 }, | |
323 | [M_SYSREG_PSPLIM] = { "psplim", ARM_FEATURE_V8 }, | |
324 | }; | |
325 | ||
326 | static uint32_t *m_sysreg_ptr(CPUARMState *env, MProfileSysreg reg, bool sec) | |
327 | { | |
328 | uint32_t *ptr; | |
329 | ||
330 | switch (reg) { | |
331 | case M_SYSREG_MSP: | |
332 | ptr = arm_v7m_get_sp_ptr(env, sec, false, true); | |
333 | break; | |
334 | case M_SYSREG_PSP: | |
335 | ptr = arm_v7m_get_sp_ptr(env, sec, true, true); | |
336 | break; | |
337 | case M_SYSREG_MSPLIM: | |
338 | ptr = &env->v7m.msplim[sec]; | |
339 | break; | |
340 | case M_SYSREG_PSPLIM: | |
341 | ptr = &env->v7m.psplim[sec]; | |
342 | break; | |
343 | case M_SYSREG_PRIMASK: | |
344 | ptr = &env->v7m.primask[sec]; | |
345 | break; | |
346 | case M_SYSREG_BASEPRI: | |
347 | ptr = &env->v7m.basepri[sec]; | |
348 | break; | |
349 | case M_SYSREG_FAULTMASK: | |
350 | ptr = &env->v7m.faultmask[sec]; | |
351 | break; | |
352 | case M_SYSREG_CONTROL: | |
353 | ptr = &env->v7m.control[sec]; | |
354 | break; | |
355 | default: | |
356 | return NULL; | |
357 | } | |
358 | return arm_feature(env, m_sysreg_def[reg].feature) ? ptr : NULL; | |
359 | } | |
360 | ||
361 | static int m_sysreg_get(CPUARMState *env, GByteArray *buf, | |
362 | MProfileSysreg reg, bool secure) | |
363 | { | |
364 | uint32_t *ptr = m_sysreg_ptr(env, reg, secure); | |
365 | ||
366 | if (ptr == NULL) { | |
367 | return 0; | |
368 | } | |
369 | return gdb_get_reg32(buf, *ptr); | |
370 | } | |
371 | ||
372 | static int arm_gdb_get_m_systemreg(CPUARMState *env, GByteArray *buf, int reg) | |
373 | { | |
374 | /* | |
375 | * Here, we emulate MRS instruction, where CONTROL has a mix of | |
376 | * banked and non-banked bits. | |
377 | */ | |
378 | if (reg == M_SYSREG_CONTROL) { | |
379 | return gdb_get_reg32(buf, arm_v7m_mrs_control(env, env->v7m.secure)); | |
380 | } | |
381 | return m_sysreg_get(env, buf, reg, env->v7m.secure); | |
382 | } | |
383 | ||
384 | static int arm_gdb_set_m_systemreg(CPUARMState *env, uint8_t *buf, int reg) | |
385 | { | |
386 | return 0; /* TODO */ | |
387 | } | |
388 | ||
389 | static int arm_gen_dynamic_m_systemreg_xml(CPUState *cs, int orig_base_reg) | |
390 | { | |
391 | ARMCPU *cpu = ARM_CPU(cs); | |
392 | CPUARMState *env = &cpu->env; | |
393 | GString *s = g_string_new(NULL); | |
394 | int base_reg = orig_base_reg; | |
395 | int i; | |
396 | ||
397 | g_string_printf(s, "<?xml version=\"1.0\"?>"); | |
398 | g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">"); | |
399 | g_string_append_printf(s, "<feature name=\"org.gnu.gdb.arm.m-system\">\n"); | |
400 | ||
401 | for (i = 0; i < ARRAY_SIZE(m_sysreg_def); i++) { | |
402 | if (arm_feature(env, m_sysreg_def[i].feature)) { | |
403 | g_string_append_printf(s, | |
404 | "<reg name=\"%s\" bitsize=\"32\" regnum=\"%d\"/>\n", | |
405 | m_sysreg_def[i].name, base_reg++); | |
406 | } | |
407 | } | |
408 | ||
409 | g_string_append_printf(s, "</feature>"); | |
410 | cpu->dyn_m_systemreg_xml.desc = g_string_free(s, false); | |
411 | cpu->dyn_m_systemreg_xml.num = base_reg - orig_base_reg; | |
412 | ||
413 | return cpu->dyn_m_systemreg_xml.num; | |
414 | } | |
415 | ||
416 | #ifndef CONFIG_USER_ONLY | |
417 | /* | |
418 | * For user-only, we see the non-secure registers via m_systemreg above. | |
419 | * For secext, encode the non-secure view as even and secure view as odd. | |
420 | */ | |
421 | static int arm_gdb_get_m_secextreg(CPUARMState *env, GByteArray *buf, int reg) | |
422 | { | |
423 | return m_sysreg_get(env, buf, reg >> 1, reg & 1); | |
424 | } | |
425 | ||
426 | static int arm_gdb_set_m_secextreg(CPUARMState *env, uint8_t *buf, int reg) | |
427 | { | |
428 | return 0; /* TODO */ | |
429 | } | |
430 | ||
431 | static int arm_gen_dynamic_m_secextreg_xml(CPUState *cs, int orig_base_reg) | |
432 | { | |
433 | ARMCPU *cpu = ARM_CPU(cs); | |
434 | GString *s = g_string_new(NULL); | |
435 | int base_reg = orig_base_reg; | |
436 | int i; | |
437 | ||
438 | g_string_printf(s, "<?xml version=\"1.0\"?>"); | |
439 | g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">"); | |
440 | g_string_append_printf(s, "<feature name=\"org.gnu.gdb.arm.secext\">\n"); | |
441 | ||
442 | for (i = 0; i < ARRAY_SIZE(m_sysreg_def); i++) { | |
443 | g_string_append_printf(s, | |
444 | "<reg name=\"%s_ns\" bitsize=\"32\" regnum=\"%d\"/>\n", | |
445 | m_sysreg_def[i].name, base_reg++); | |
446 | g_string_append_printf(s, | |
447 | "<reg name=\"%s_s\" bitsize=\"32\" regnum=\"%d\"/>\n", | |
448 | m_sysreg_def[i].name, base_reg++); | |
449 | } | |
450 | ||
451 | g_string_append_printf(s, "</feature>"); | |
452 | cpu->dyn_m_secextreg_xml.desc = g_string_free(s, false); | |
453 | cpu->dyn_m_secextreg_xml.num = base_reg - orig_base_reg; | |
454 | ||
455 | return cpu->dyn_m_secextreg_xml.num; | |
456 | } | |
457 | #endif | |
893ca916 | 458 | #endif /* CONFIG_TCG */ |
7d8b28b8 | 459 | |
200bf5b7 AB |
460 | const char *arm_gdb_get_dynamic_xml(CPUState *cs, const char *xmlname) |
461 | { | |
462 | ARMCPU *cpu = ARM_CPU(cs); | |
463 | ||
464 | if (strcmp(xmlname, "system-registers.xml") == 0) { | |
448d4d14 | 465 | return cpu->dyn_sysreg_xml.desc; |
d12379c5 AB |
466 | } else if (strcmp(xmlname, "sve-registers.xml") == 0) { |
467 | return cpu->dyn_svereg_xml.desc; | |
7d8b28b8 RH |
468 | } else if (strcmp(xmlname, "arm-m-system.xml") == 0) { |
469 | return cpu->dyn_m_systemreg_xml.desc; | |
470 | #ifndef CONFIG_USER_ONLY | |
471 | } else if (strcmp(xmlname, "arm-m-secext.xml") == 0) { | |
472 | return cpu->dyn_m_secextreg_xml.desc; | |
473 | #endif | |
200bf5b7 AB |
474 | } |
475 | return NULL; | |
476 | } | |
89f4f20e PM |
477 | |
478 | void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu) | |
479 | { | |
480 | CPUState *cs = CPU(cpu); | |
481 | CPUARMState *env = &cpu->env; | |
482 | ||
483 | if (arm_feature(env, ARM_FEATURE_AARCH64)) { | |
484 | /* | |
485 | * The lower part of each SVE register aliases to the FPU | |
486 | * registers so we don't need to include both. | |
487 | */ | |
488 | #ifdef TARGET_AARCH64 | |
489 | if (isar_feature_aa64_sve(&cpu->isar)) { | |
963a6b91 RH |
490 | int nreg = arm_gen_dynamic_svereg_xml(cs, cs->gdb_num_regs); |
491 | gdb_register_coprocessor(cs, aarch64_gdb_get_sve_reg, | |
492 | aarch64_gdb_set_sve_reg, nreg, | |
89f4f20e PM |
493 | "sve-registers.xml", 0); |
494 | } else { | |
963a6b91 RH |
495 | gdb_register_coprocessor(cs, aarch64_gdb_get_fpu_reg, |
496 | aarch64_gdb_set_fpu_reg, | |
89f4f20e PM |
497 | 34, "aarch64-fpu.xml", 0); |
498 | } | |
5787d17a | 499 | /* |
7bdd67a5 PM |
500 | * Note that we report pauth information via the feature name |
501 | * org.gnu.gdb.aarch64.pauth_v2, not org.gnu.gdb.aarch64.pauth. | |
502 | * GDB versions 9 through 12 have a bug where they will crash | |
503 | * if they see the latter XML from QEMU. | |
5787d17a | 504 | */ |
e995d5cc RH |
505 | if (isar_feature_aa64_pauth(&cpu->isar)) { |
506 | gdb_register_coprocessor(cs, aarch64_gdb_get_pauth_reg, | |
507 | aarch64_gdb_set_pauth_reg, | |
508 | 4, "aarch64-pauth.xml", 0); | |
509 | } | |
89f4f20e | 510 | #endif |
b355f08a PM |
511 | } else { |
512 | if (arm_feature(env, ARM_FEATURE_NEON)) { | |
513 | gdb_register_coprocessor(cs, vfp_gdb_get_reg, vfp_gdb_set_reg, | |
514 | 49, "arm-neon.xml", 0); | |
515 | } else if (cpu_isar_feature(aa32_simd_r32, cpu)) { | |
516 | gdb_register_coprocessor(cs, vfp_gdb_get_reg, vfp_gdb_set_reg, | |
517 | 33, "arm-vfp3.xml", 0); | |
518 | } else if (cpu_isar_feature(aa32_vfp_simd, cpu)) { | |
519 | gdb_register_coprocessor(cs, vfp_gdb_get_reg, vfp_gdb_set_reg, | |
520 | 17, "arm-vfp.xml", 0); | |
521 | } | |
522 | if (!arm_feature(env, ARM_FEATURE_M)) { | |
523 | /* | |
524 | * A and R profile have FP sysregs FPEXC and FPSID that we | |
525 | * expose to gdb. | |
526 | */ | |
527 | gdb_register_coprocessor(cs, vfp_gdb_get_sysreg, vfp_gdb_set_sysreg, | |
528 | 2, "arm-vfp-sysregs.xml", 0); | |
529 | } | |
89f4f20e | 530 | } |
46e3b237 | 531 | if (cpu_isar_feature(aa32_mve, cpu) && tcg_enabled()) { |
dbd9e084 PM |
532 | gdb_register_coprocessor(cs, mve_gdb_get_reg, mve_gdb_set_reg, |
533 | 1, "arm-m-profile-mve.xml", 0); | |
534 | } | |
89f4f20e PM |
535 | gdb_register_coprocessor(cs, arm_gdb_get_sysreg, arm_gdb_set_sysreg, |
536 | arm_gen_dynamic_sysreg_xml(cs, cs->gdb_num_regs), | |
537 | "system-registers.xml", 0); | |
538 | ||
893ca916 | 539 | #ifdef CONFIG_TCG |
46e3b237 | 540 | if (arm_feature(env, ARM_FEATURE_M) && tcg_enabled()) { |
7d8b28b8 RH |
541 | gdb_register_coprocessor(cs, |
542 | arm_gdb_get_m_systemreg, arm_gdb_set_m_systemreg, | |
543 | arm_gen_dynamic_m_systemreg_xml(cs, cs->gdb_num_regs), | |
544 | "arm-m-system.xml", 0); | |
545 | #ifndef CONFIG_USER_ONLY | |
546 | if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { | |
547 | gdb_register_coprocessor(cs, | |
548 | arm_gdb_get_m_secextreg, arm_gdb_set_m_secextreg, | |
549 | arm_gen_dynamic_m_secextreg_xml(cs, cs->gdb_num_regs), | |
550 | "arm-m-secext.xml", 0); | |
551 | } | |
552 | #endif | |
553 | } | |
893ca916 | 554 | #endif /* CONFIG_TCG */ |
89f4f20e | 555 | } |