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