xref: /openbmc/qemu/target/arm/gdbstub.c (revision 46e3b237c52e0c48bfd81bce020b51fbe300b23a)
1fcf5ef2aSThomas Huth /*
2fcf5ef2aSThomas Huth  * ARM gdb server stub
3fcf5ef2aSThomas Huth  *
4fcf5ef2aSThomas Huth  * Copyright (c) 2003-2005 Fabrice Bellard
5fcf5ef2aSThomas Huth  * Copyright (c) 2013 SUSE LINUX Products GmbH
6fcf5ef2aSThomas Huth  *
7fcf5ef2aSThomas Huth  * This library is free software; you can redistribute it and/or
8fcf5ef2aSThomas Huth  * modify it under the terms of the GNU Lesser General Public
9fcf5ef2aSThomas Huth  * License as published by the Free Software Foundation; either
1050f57e09SChetan Pant  * version 2.1 of the License, or (at your option) any later version.
11fcf5ef2aSThomas Huth  *
12fcf5ef2aSThomas Huth  * This library is distributed in the hope that it will be useful,
13fcf5ef2aSThomas Huth  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14fcf5ef2aSThomas Huth  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15fcf5ef2aSThomas Huth  * Lesser General Public License for more details.
16fcf5ef2aSThomas Huth  *
17fcf5ef2aSThomas Huth  * You should have received a copy of the GNU Lesser General Public
18fcf5ef2aSThomas Huth  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19fcf5ef2aSThomas Huth  */
20fcf5ef2aSThomas Huth #include "qemu/osdep.h"
21fcf5ef2aSThomas Huth #include "cpu.h"
22fcf5ef2aSThomas Huth #include "exec/gdbstub.h"
234ea5fe99SAlex Bennée #include "gdbstub/helpers.h"
24*46e3b237SPhilippe Mathieu-Daudé #include "sysemu/tcg.h"
25cf7c6d10SRichard Henderson #include "internals.h"
26cf7c6d10SRichard Henderson #include "cpregs.h"
27fcf5ef2aSThomas Huth 
28200bf5b7SAbdallah Bouassida typedef struct RegisterSysregXmlParam {
29200bf5b7SAbdallah Bouassida     CPUState *cs;
30200bf5b7SAbdallah Bouassida     GString *s;
3132d6e32aSAlex Bennée     int n;
32200bf5b7SAbdallah Bouassida } RegisterSysregXmlParam;
33200bf5b7SAbdallah Bouassida 
34fcf5ef2aSThomas Huth /* Old gdb always expect FPA registers.  Newer (xml-aware) gdb only expect
35fcf5ef2aSThomas Huth    whatever the target description contains.  Due to a historical mishap
36fcf5ef2aSThomas Huth    the FPA registers appear in between core integer regs and the CPSR.
37fcf5ef2aSThomas Huth    We hack round this by giving the FPA regs zero size when talking to a
38fcf5ef2aSThomas Huth    newer gdb.  */
39fcf5ef2aSThomas Huth 
40a010bdbeSAlex Bennée int arm_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
41fcf5ef2aSThomas Huth {
42fcf5ef2aSThomas Huth     ARMCPU *cpu = ARM_CPU(cs);
43fcf5ef2aSThomas Huth     CPUARMState *env = &cpu->env;
44fcf5ef2aSThomas Huth 
45fcf5ef2aSThomas Huth     if (n < 16) {
46fcf5ef2aSThomas Huth         /* Core integer register.  */
47fcf5ef2aSThomas Huth         return gdb_get_reg32(mem_buf, env->regs[n]);
48fcf5ef2aSThomas Huth     }
49fcf5ef2aSThomas Huth     if (n < 24) {
50fcf5ef2aSThomas Huth         /* FPA registers.  */
51fcf5ef2aSThomas Huth         if (gdb_has_xml) {
52fcf5ef2aSThomas Huth             return 0;
53fcf5ef2aSThomas Huth         }
547b8c1527SPhilippe Mathieu-Daudé         return gdb_get_zeroes(mem_buf, 12);
55fcf5ef2aSThomas Huth     }
56fcf5ef2aSThomas Huth     switch (n) {
57fcf5ef2aSThomas Huth     case 24:
58fcf5ef2aSThomas Huth         /* FPA status register.  */
59fcf5ef2aSThomas Huth         if (gdb_has_xml) {
60fcf5ef2aSThomas Huth             return 0;
61fcf5ef2aSThomas Huth         }
62fcf5ef2aSThomas Huth         return gdb_get_reg32(mem_buf, 0);
63fcf5ef2aSThomas Huth     case 25:
64c888f7e0SPeter Maydell         /* CPSR, or XPSR for M-profile */
65c888f7e0SPeter Maydell         if (arm_feature(env, ARM_FEATURE_M)) {
66c888f7e0SPeter Maydell             return gdb_get_reg32(mem_buf, xpsr_read(env));
67c888f7e0SPeter Maydell         } else {
68fcf5ef2aSThomas Huth             return gdb_get_reg32(mem_buf, cpsr_read(env));
69fcf5ef2aSThomas Huth         }
70c888f7e0SPeter Maydell     }
71fcf5ef2aSThomas Huth     /* Unknown register.  */
72fcf5ef2aSThomas Huth     return 0;
73fcf5ef2aSThomas Huth }
74fcf5ef2aSThomas Huth 
75fcf5ef2aSThomas Huth int arm_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
76fcf5ef2aSThomas Huth {
77fcf5ef2aSThomas Huth     ARMCPU *cpu = ARM_CPU(cs);
78fcf5ef2aSThomas Huth     CPUARMState *env = &cpu->env;
79fcf5ef2aSThomas Huth     uint32_t tmp;
80fcf5ef2aSThomas Huth 
81fcf5ef2aSThomas Huth     tmp = ldl_p(mem_buf);
82fcf5ef2aSThomas Huth 
837055fe4bSRichard Henderson     /*
847055fe4bSRichard Henderson      * Mask out low bits of PC to workaround gdb bugs.
857055fe4bSRichard Henderson      * This avoids an assert in thumb_tr_translate_insn, because it is
867055fe4bSRichard Henderson      * architecturally impossible to misalign the pc.
877055fe4bSRichard Henderson      * This will probably cause problems if we ever implement the
887055fe4bSRichard Henderson      * Jazelle DBX extensions.
897055fe4bSRichard Henderson      */
90fcf5ef2aSThomas Huth     if (n == 15) {
91fcf5ef2aSThomas Huth         tmp &= ~1;
92fcf5ef2aSThomas Huth     }
93fcf5ef2aSThomas Huth 
94fcf5ef2aSThomas Huth     if (n < 16) {
95fcf5ef2aSThomas Huth         /* Core integer register.  */
96888f470fSPeter Maydell         if (n == 13 && arm_feature(env, ARM_FEATURE_M)) {
97888f470fSPeter Maydell             /* M profile SP low bits are always 0 */
98888f470fSPeter Maydell             tmp &= ~3;
99888f470fSPeter Maydell         }
100fcf5ef2aSThomas Huth         env->regs[n] = tmp;
101fcf5ef2aSThomas Huth         return 4;
102fcf5ef2aSThomas Huth     }
103fcf5ef2aSThomas Huth     if (n < 24) { /* 16-23 */
104fcf5ef2aSThomas Huth         /* FPA registers (ignored).  */
105fcf5ef2aSThomas Huth         if (gdb_has_xml) {
106fcf5ef2aSThomas Huth             return 0;
107fcf5ef2aSThomas Huth         }
108fcf5ef2aSThomas Huth         return 12;
109fcf5ef2aSThomas Huth     }
110fcf5ef2aSThomas Huth     switch (n) {
111fcf5ef2aSThomas Huth     case 24:
112fcf5ef2aSThomas Huth         /* FPA status register (ignored).  */
113fcf5ef2aSThomas Huth         if (gdb_has_xml) {
114fcf5ef2aSThomas Huth             return 0;
115fcf5ef2aSThomas Huth         }
116fcf5ef2aSThomas Huth         return 4;
117fcf5ef2aSThomas Huth     case 25:
118c888f7e0SPeter Maydell         /* CPSR, or XPSR for M-profile */
119c888f7e0SPeter Maydell         if (arm_feature(env, ARM_FEATURE_M)) {
120c888f7e0SPeter Maydell             /*
121c888f7e0SPeter Maydell              * Don't allow writing to XPSR.Exception as it can cause
122c888f7e0SPeter Maydell              * a transition into or out of handler mode (it's not
1239323e79fSPeter Maydell              * writable via the MSR insn so this is a reasonable
124c888f7e0SPeter Maydell              * restriction). Other fields are safe to update.
125c888f7e0SPeter Maydell              */
126c888f7e0SPeter Maydell             xpsr_write(env, tmp, ~XPSR_EXCP);
127c888f7e0SPeter Maydell         } else {
128fcf5ef2aSThomas Huth             cpsr_write(env, tmp, 0xffffffff, CPSRWriteByGDBStub);
129c888f7e0SPeter Maydell         }
130fcf5ef2aSThomas Huth         return 4;
131fcf5ef2aSThomas Huth     }
132fcf5ef2aSThomas Huth     /* Unknown register.  */
133fcf5ef2aSThomas Huth     return 0;
134fcf5ef2aSThomas Huth }
135200bf5b7SAbdallah Bouassida 
13689f4f20eSPeter Maydell static int vfp_gdb_get_reg(CPUARMState *env, GByteArray *buf, int reg)
13789f4f20eSPeter Maydell {
13889f4f20eSPeter Maydell     ARMCPU *cpu = env_archcpu(env);
13989f4f20eSPeter Maydell     int nregs = cpu_isar_feature(aa32_simd_r32, cpu) ? 32 : 16;
14089f4f20eSPeter Maydell 
14189f4f20eSPeter Maydell     /* VFP data registers are always little-endian.  */
14289f4f20eSPeter Maydell     if (reg < nregs) {
14389f4f20eSPeter Maydell         return gdb_get_reg64(buf, *aa32_vfp_dreg(env, reg));
14489f4f20eSPeter Maydell     }
14589f4f20eSPeter Maydell     if (arm_feature(env, ARM_FEATURE_NEON)) {
14689f4f20eSPeter Maydell         /* Aliases for Q regs.  */
14789f4f20eSPeter Maydell         nregs += 16;
14889f4f20eSPeter Maydell         if (reg < nregs) {
14989f4f20eSPeter Maydell             uint64_t *q = aa32_vfp_qreg(env, reg - 32);
15089f4f20eSPeter Maydell             return gdb_get_reg128(buf, q[0], q[1]);
15189f4f20eSPeter Maydell         }
15289f4f20eSPeter Maydell     }
15389f4f20eSPeter Maydell     switch (reg - nregs) {
15489f4f20eSPeter Maydell     case 0:
15589f4f20eSPeter Maydell         return gdb_get_reg32(buf, vfp_get_fpscr(env));
15689f4f20eSPeter Maydell     }
15789f4f20eSPeter Maydell     return 0;
15889f4f20eSPeter Maydell }
15989f4f20eSPeter Maydell 
16089f4f20eSPeter Maydell static int vfp_gdb_set_reg(CPUARMState *env, uint8_t *buf, int reg)
16189f4f20eSPeter Maydell {
16289f4f20eSPeter Maydell     ARMCPU *cpu = env_archcpu(env);
16389f4f20eSPeter Maydell     int nregs = cpu_isar_feature(aa32_simd_r32, cpu) ? 32 : 16;
16489f4f20eSPeter Maydell 
16589f4f20eSPeter Maydell     if (reg < nregs) {
16689f4f20eSPeter Maydell         *aa32_vfp_dreg(env, reg) = ldq_le_p(buf);
16789f4f20eSPeter Maydell         return 8;
16889f4f20eSPeter Maydell     }
16989f4f20eSPeter Maydell     if (arm_feature(env, ARM_FEATURE_NEON)) {
17089f4f20eSPeter Maydell         nregs += 16;
17189f4f20eSPeter Maydell         if (reg < nregs) {
17289f4f20eSPeter Maydell             uint64_t *q = aa32_vfp_qreg(env, reg - 32);
17389f4f20eSPeter Maydell             q[0] = ldq_le_p(buf);
17489f4f20eSPeter Maydell             q[1] = ldq_le_p(buf + 8);
17589f4f20eSPeter Maydell             return 16;
17689f4f20eSPeter Maydell         }
17789f4f20eSPeter Maydell     }
17889f4f20eSPeter Maydell     switch (reg - nregs) {
17989f4f20eSPeter Maydell     case 0:
180b355f08aSPeter Maydell         vfp_set_fpscr(env, ldl_p(buf));
181b355f08aSPeter Maydell         return 4;
182b355f08aSPeter Maydell     }
183b355f08aSPeter Maydell     return 0;
184b355f08aSPeter Maydell }
185b355f08aSPeter Maydell 
186b355f08aSPeter Maydell static int vfp_gdb_get_sysreg(CPUARMState *env, GByteArray *buf, int reg)
187b355f08aSPeter Maydell {
188b355f08aSPeter Maydell     switch (reg) {
189b355f08aSPeter Maydell     case 0:
190b355f08aSPeter Maydell         return gdb_get_reg32(buf, env->vfp.xregs[ARM_VFP_FPSID]);
191b355f08aSPeter Maydell     case 1:
192b355f08aSPeter Maydell         return gdb_get_reg32(buf, env->vfp.xregs[ARM_VFP_FPEXC]);
193b355f08aSPeter Maydell     }
194b355f08aSPeter Maydell     return 0;
195b355f08aSPeter Maydell }
196b355f08aSPeter Maydell 
197b355f08aSPeter Maydell static int vfp_gdb_set_sysreg(CPUARMState *env, uint8_t *buf, int reg)
198b355f08aSPeter Maydell {
199b355f08aSPeter Maydell     switch (reg) {
200b355f08aSPeter Maydell     case 0:
20189f4f20eSPeter Maydell         env->vfp.xregs[ARM_VFP_FPSID] = ldl_p(buf);
20289f4f20eSPeter Maydell         return 4;
20389f4f20eSPeter Maydell     case 1:
20489f4f20eSPeter Maydell         env->vfp.xregs[ARM_VFP_FPEXC] = ldl_p(buf) & (1 << 30);
20589f4f20eSPeter Maydell         return 4;
20689f4f20eSPeter Maydell     }
20789f4f20eSPeter Maydell     return 0;
20889f4f20eSPeter Maydell }
20989f4f20eSPeter Maydell 
210dbd9e084SPeter Maydell static int mve_gdb_get_reg(CPUARMState *env, GByteArray *buf, int reg)
211dbd9e084SPeter Maydell {
212dbd9e084SPeter Maydell     switch (reg) {
213dbd9e084SPeter Maydell     case 0:
214dbd9e084SPeter Maydell         return gdb_get_reg32(buf, env->v7m.vpr);
215dbd9e084SPeter Maydell     default:
216dbd9e084SPeter Maydell         return 0;
217dbd9e084SPeter Maydell     }
218dbd9e084SPeter Maydell }
219dbd9e084SPeter Maydell 
220dbd9e084SPeter Maydell static int mve_gdb_set_reg(CPUARMState *env, uint8_t *buf, int reg)
221dbd9e084SPeter Maydell {
222dbd9e084SPeter Maydell     switch (reg) {
223dbd9e084SPeter Maydell     case 0:
224dbd9e084SPeter Maydell         env->v7m.vpr = ldl_p(buf);
225dbd9e084SPeter Maydell         return 4;
226dbd9e084SPeter Maydell     default:
227dbd9e084SPeter Maydell         return 0;
228dbd9e084SPeter Maydell     }
229dbd9e084SPeter Maydell }
230dbd9e084SPeter Maydell 
23189f4f20eSPeter Maydell /**
23289f4f20eSPeter Maydell  * arm_get/set_gdb_*: get/set a gdb register
23389f4f20eSPeter Maydell  * @env: the CPU state
23489f4f20eSPeter Maydell  * @buf: a buffer to copy to/from
23589f4f20eSPeter Maydell  * @reg: register number (offset from start of group)
23689f4f20eSPeter Maydell  *
23789f4f20eSPeter Maydell  * We return the number of bytes copied
23889f4f20eSPeter Maydell  */
23989f4f20eSPeter Maydell 
24089f4f20eSPeter Maydell static int arm_gdb_get_sysreg(CPUARMState *env, GByteArray *buf, int reg)
24189f4f20eSPeter Maydell {
24289f4f20eSPeter Maydell     ARMCPU *cpu = env_archcpu(env);
24389f4f20eSPeter Maydell     const ARMCPRegInfo *ri;
24489f4f20eSPeter Maydell     uint32_t key;
24589f4f20eSPeter Maydell 
24689f4f20eSPeter Maydell     key = cpu->dyn_sysreg_xml.data.cpregs.keys[reg];
24789f4f20eSPeter Maydell     ri = get_arm_cp_reginfo(cpu->cp_regs, key);
24889f4f20eSPeter Maydell     if (ri) {
24989f4f20eSPeter Maydell         if (cpreg_field_is_64bit(ri)) {
25089f4f20eSPeter Maydell             return gdb_get_reg64(buf, (uint64_t)read_raw_cp_reg(env, ri));
25189f4f20eSPeter Maydell         } else {
25289f4f20eSPeter Maydell             return gdb_get_reg32(buf, (uint32_t)read_raw_cp_reg(env, ri));
25389f4f20eSPeter Maydell         }
25489f4f20eSPeter Maydell     }
25589f4f20eSPeter Maydell     return 0;
25689f4f20eSPeter Maydell }
25789f4f20eSPeter Maydell 
25889f4f20eSPeter Maydell static int arm_gdb_set_sysreg(CPUARMState *env, uint8_t *buf, int reg)
25989f4f20eSPeter Maydell {
26089f4f20eSPeter Maydell     return 0;
26189f4f20eSPeter Maydell }
26289f4f20eSPeter Maydell 
263448d4d14SAlex Bennée static void arm_gen_one_xml_sysreg_tag(GString *s, DynamicGDBXMLInfo *dyn_xml,
264200bf5b7SAbdallah Bouassida                                        ARMCPRegInfo *ri, uint32_t ri_key,
26532d6e32aSAlex Bennée                                        int bitsize, int regnum)
266200bf5b7SAbdallah Bouassida {
267200bf5b7SAbdallah Bouassida     g_string_append_printf(s, "<reg name=\"%s\"", ri->name);
268200bf5b7SAbdallah Bouassida     g_string_append_printf(s, " bitsize=\"%d\"", bitsize);
26932d6e32aSAlex Bennée     g_string_append_printf(s, " regnum=\"%d\"", regnum);
270200bf5b7SAbdallah Bouassida     g_string_append_printf(s, " group=\"cp_regs\"/>");
271448d4d14SAlex Bennée     dyn_xml->data.cpregs.keys[dyn_xml->num] = ri_key;
272448d4d14SAlex Bennée     dyn_xml->num++;
273200bf5b7SAbdallah Bouassida }
274200bf5b7SAbdallah Bouassida 
275200bf5b7SAbdallah Bouassida static void arm_register_sysreg_for_xml(gpointer key, gpointer value,
276200bf5b7SAbdallah Bouassida                                         gpointer p)
277200bf5b7SAbdallah Bouassida {
2785860362dSRichard Henderson     uint32_t ri_key = (uintptr_t)key;
279200bf5b7SAbdallah Bouassida     ARMCPRegInfo *ri = value;
280200bf5b7SAbdallah Bouassida     RegisterSysregXmlParam *param = (RegisterSysregXmlParam *)p;
281200bf5b7SAbdallah Bouassida     GString *s = param->s;
282200bf5b7SAbdallah Bouassida     ARMCPU *cpu = ARM_CPU(param->cs);
283200bf5b7SAbdallah Bouassida     CPUARMState *env = &cpu->env;
284448d4d14SAlex Bennée     DynamicGDBXMLInfo *dyn_xml = &cpu->dyn_sysreg_xml;
285200bf5b7SAbdallah Bouassida 
286200bf5b7SAbdallah Bouassida     if (!(ri->type & (ARM_CP_NO_RAW | ARM_CP_NO_GDB))) {
287200bf5b7SAbdallah Bouassida         if (arm_feature(env, ARM_FEATURE_AARCH64)) {
288200bf5b7SAbdallah Bouassida             if (ri->state == ARM_CP_STATE_AA64) {
28932d6e32aSAlex Bennée                 arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 64,
29032d6e32aSAlex Bennée                                            param->n++);
291200bf5b7SAbdallah Bouassida             }
292200bf5b7SAbdallah Bouassida         } else {
293200bf5b7SAbdallah Bouassida             if (ri->state == ARM_CP_STATE_AA32) {
294200bf5b7SAbdallah Bouassida                 if (!arm_feature(env, ARM_FEATURE_EL3) &&
295200bf5b7SAbdallah Bouassida                     (ri->secure & ARM_CP_SECSTATE_S)) {
296200bf5b7SAbdallah Bouassida                     return;
297200bf5b7SAbdallah Bouassida                 }
298200bf5b7SAbdallah Bouassida                 if (ri->type & ARM_CP_64BIT) {
29932d6e32aSAlex Bennée                     arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 64,
30032d6e32aSAlex Bennée                                                param->n++);
301200bf5b7SAbdallah Bouassida                 } else {
30232d6e32aSAlex Bennée                     arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 32,
30332d6e32aSAlex Bennée                                                param->n++);
304200bf5b7SAbdallah Bouassida                 }
305200bf5b7SAbdallah Bouassida             }
306200bf5b7SAbdallah Bouassida         }
307200bf5b7SAbdallah Bouassida     }
308200bf5b7SAbdallah Bouassida }
309200bf5b7SAbdallah Bouassida 
3104bce95b4SRichard Henderson static int arm_gen_dynamic_sysreg_xml(CPUState *cs, int base_reg)
311200bf5b7SAbdallah Bouassida {
312200bf5b7SAbdallah Bouassida     ARMCPU *cpu = ARM_CPU(cs);
313200bf5b7SAbdallah Bouassida     GString *s = g_string_new(NULL);
31432d6e32aSAlex Bennée     RegisterSysregXmlParam param = {cs, s, base_reg};
315200bf5b7SAbdallah Bouassida 
316448d4d14SAlex Bennée     cpu->dyn_sysreg_xml.num = 0;
317448d4d14SAlex Bennée     cpu->dyn_sysreg_xml.data.cpregs.keys = g_new(uint32_t, g_hash_table_size(cpu->cp_regs));
318200bf5b7SAbdallah Bouassida     g_string_printf(s, "<?xml version=\"1.0\"?>");
319200bf5b7SAbdallah Bouassida     g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">");
320200bf5b7SAbdallah Bouassida     g_string_append_printf(s, "<feature name=\"org.qemu.gdb.arm.sys.regs\">");
321200bf5b7SAbdallah Bouassida     g_hash_table_foreach(cpu->cp_regs, arm_register_sysreg_for_xml, &param);
322200bf5b7SAbdallah Bouassida     g_string_append_printf(s, "</feature>");
323448d4d14SAlex Bennée     cpu->dyn_sysreg_xml.desc = g_string_free(s, false);
324448d4d14SAlex Bennée     return cpu->dyn_sysreg_xml.num;
325200bf5b7SAbdallah Bouassida }
326200bf5b7SAbdallah Bouassida 
3277d8b28b8SRichard Henderson typedef enum {
3287d8b28b8SRichard Henderson     M_SYSREG_MSP,
3297d8b28b8SRichard Henderson     M_SYSREG_PSP,
3307d8b28b8SRichard Henderson     M_SYSREG_PRIMASK,
3317d8b28b8SRichard Henderson     M_SYSREG_CONTROL,
3327d8b28b8SRichard Henderson     M_SYSREG_BASEPRI,
3337d8b28b8SRichard Henderson     M_SYSREG_FAULTMASK,
3347d8b28b8SRichard Henderson     M_SYSREG_MSPLIM,
3357d8b28b8SRichard Henderson     M_SYSREG_PSPLIM,
3367d8b28b8SRichard Henderson } MProfileSysreg;
3377d8b28b8SRichard Henderson 
3387d8b28b8SRichard Henderson static const struct {
3397d8b28b8SRichard Henderson     const char *name;
3407d8b28b8SRichard Henderson     int feature;
3417d8b28b8SRichard Henderson } m_sysreg_def[] = {
3427d8b28b8SRichard Henderson     [M_SYSREG_MSP] = { "msp", ARM_FEATURE_M },
3437d8b28b8SRichard Henderson     [M_SYSREG_PSP] = { "psp", ARM_FEATURE_M },
3447d8b28b8SRichard Henderson     [M_SYSREG_PRIMASK] = { "primask", ARM_FEATURE_M },
3457d8b28b8SRichard Henderson     [M_SYSREG_CONTROL] = { "control", ARM_FEATURE_M },
3467d8b28b8SRichard Henderson     [M_SYSREG_BASEPRI] = { "basepri", ARM_FEATURE_M_MAIN },
3477d8b28b8SRichard Henderson     [M_SYSREG_FAULTMASK] = { "faultmask", ARM_FEATURE_M_MAIN },
3487d8b28b8SRichard Henderson     [M_SYSREG_MSPLIM] = { "msplim", ARM_FEATURE_V8 },
3497d8b28b8SRichard Henderson     [M_SYSREG_PSPLIM] = { "psplim", ARM_FEATURE_V8 },
3507d8b28b8SRichard Henderson };
3517d8b28b8SRichard Henderson 
3527d8b28b8SRichard Henderson static uint32_t *m_sysreg_ptr(CPUARMState *env, MProfileSysreg reg, bool sec)
3537d8b28b8SRichard Henderson {
3547d8b28b8SRichard Henderson     uint32_t *ptr;
3557d8b28b8SRichard Henderson 
3567d8b28b8SRichard Henderson     switch (reg) {
3577d8b28b8SRichard Henderson     case M_SYSREG_MSP:
3587d8b28b8SRichard Henderson         ptr = arm_v7m_get_sp_ptr(env, sec, false, true);
3597d8b28b8SRichard Henderson         break;
3607d8b28b8SRichard Henderson     case M_SYSREG_PSP:
3617d8b28b8SRichard Henderson         ptr = arm_v7m_get_sp_ptr(env, sec, true, true);
3627d8b28b8SRichard Henderson         break;
3637d8b28b8SRichard Henderson     case M_SYSREG_MSPLIM:
3647d8b28b8SRichard Henderson         ptr = &env->v7m.msplim[sec];
3657d8b28b8SRichard Henderson         break;
3667d8b28b8SRichard Henderson     case M_SYSREG_PSPLIM:
3677d8b28b8SRichard Henderson         ptr = &env->v7m.psplim[sec];
3687d8b28b8SRichard Henderson         break;
3697d8b28b8SRichard Henderson     case M_SYSREG_PRIMASK:
3707d8b28b8SRichard Henderson         ptr = &env->v7m.primask[sec];
3717d8b28b8SRichard Henderson         break;
3727d8b28b8SRichard Henderson     case M_SYSREG_BASEPRI:
3737d8b28b8SRichard Henderson         ptr = &env->v7m.basepri[sec];
3747d8b28b8SRichard Henderson         break;
3757d8b28b8SRichard Henderson     case M_SYSREG_FAULTMASK:
3767d8b28b8SRichard Henderson         ptr = &env->v7m.faultmask[sec];
3777d8b28b8SRichard Henderson         break;
3787d8b28b8SRichard Henderson     case M_SYSREG_CONTROL:
3797d8b28b8SRichard Henderson         ptr = &env->v7m.control[sec];
3807d8b28b8SRichard Henderson         break;
3817d8b28b8SRichard Henderson     default:
3827d8b28b8SRichard Henderson         return NULL;
3837d8b28b8SRichard Henderson     }
3847d8b28b8SRichard Henderson     return arm_feature(env, m_sysreg_def[reg].feature) ? ptr : NULL;
3857d8b28b8SRichard Henderson }
3867d8b28b8SRichard Henderson 
3877d8b28b8SRichard Henderson static int m_sysreg_get(CPUARMState *env, GByteArray *buf,
3887d8b28b8SRichard Henderson                         MProfileSysreg reg, bool secure)
3897d8b28b8SRichard Henderson {
3907d8b28b8SRichard Henderson     uint32_t *ptr = m_sysreg_ptr(env, reg, secure);
3917d8b28b8SRichard Henderson 
3927d8b28b8SRichard Henderson     if (ptr == NULL) {
3937d8b28b8SRichard Henderson         return 0;
3947d8b28b8SRichard Henderson     }
3957d8b28b8SRichard Henderson     return gdb_get_reg32(buf, *ptr);
3967d8b28b8SRichard Henderson }
3977d8b28b8SRichard Henderson 
3987d8b28b8SRichard Henderson static int arm_gdb_get_m_systemreg(CPUARMState *env, GByteArray *buf, int reg)
3997d8b28b8SRichard Henderson {
4007d8b28b8SRichard Henderson     /*
4017d8b28b8SRichard Henderson      * Here, we emulate MRS instruction, where CONTROL has a mix of
4027d8b28b8SRichard Henderson      * banked and non-banked bits.
4037d8b28b8SRichard Henderson      */
4047d8b28b8SRichard Henderson     if (reg == M_SYSREG_CONTROL) {
4057d8b28b8SRichard Henderson         return gdb_get_reg32(buf, arm_v7m_mrs_control(env, env->v7m.secure));
4067d8b28b8SRichard Henderson     }
4077d8b28b8SRichard Henderson     return m_sysreg_get(env, buf, reg, env->v7m.secure);
4087d8b28b8SRichard Henderson }
4097d8b28b8SRichard Henderson 
4107d8b28b8SRichard Henderson static int arm_gdb_set_m_systemreg(CPUARMState *env, uint8_t *buf, int reg)
4117d8b28b8SRichard Henderson {
4127d8b28b8SRichard Henderson     return 0; /* TODO */
4137d8b28b8SRichard Henderson }
4147d8b28b8SRichard Henderson 
4157d8b28b8SRichard Henderson static int arm_gen_dynamic_m_systemreg_xml(CPUState *cs, int orig_base_reg)
4167d8b28b8SRichard Henderson {
4177d8b28b8SRichard Henderson     ARMCPU *cpu = ARM_CPU(cs);
4187d8b28b8SRichard Henderson     CPUARMState *env = &cpu->env;
4197d8b28b8SRichard Henderson     GString *s = g_string_new(NULL);
4207d8b28b8SRichard Henderson     int base_reg = orig_base_reg;
4217d8b28b8SRichard Henderson     int i;
4227d8b28b8SRichard Henderson 
4237d8b28b8SRichard Henderson     g_string_printf(s, "<?xml version=\"1.0\"?>");
4247d8b28b8SRichard Henderson     g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">");
4257d8b28b8SRichard Henderson     g_string_append_printf(s, "<feature name=\"org.gnu.gdb.arm.m-system\">\n");
4267d8b28b8SRichard Henderson 
4277d8b28b8SRichard Henderson     for (i = 0; i < ARRAY_SIZE(m_sysreg_def); i++) {
4287d8b28b8SRichard Henderson         if (arm_feature(env, m_sysreg_def[i].feature)) {
4297d8b28b8SRichard Henderson             g_string_append_printf(s,
4307d8b28b8SRichard Henderson                 "<reg name=\"%s\" bitsize=\"32\" regnum=\"%d\"/>\n",
4317d8b28b8SRichard Henderson                 m_sysreg_def[i].name, base_reg++);
4327d8b28b8SRichard Henderson         }
4337d8b28b8SRichard Henderson     }
4347d8b28b8SRichard Henderson 
4357d8b28b8SRichard Henderson     g_string_append_printf(s, "</feature>");
4367d8b28b8SRichard Henderson     cpu->dyn_m_systemreg_xml.desc = g_string_free(s, false);
4377d8b28b8SRichard Henderson     cpu->dyn_m_systemreg_xml.num = base_reg - orig_base_reg;
4387d8b28b8SRichard Henderson 
4397d8b28b8SRichard Henderson     return cpu->dyn_m_systemreg_xml.num;
4407d8b28b8SRichard Henderson }
4417d8b28b8SRichard Henderson 
4427d8b28b8SRichard Henderson #ifndef CONFIG_USER_ONLY
4437d8b28b8SRichard Henderson /*
4447d8b28b8SRichard Henderson  * For user-only, we see the non-secure registers via m_systemreg above.
4457d8b28b8SRichard Henderson  * For secext, encode the non-secure view as even and secure view as odd.
4467d8b28b8SRichard Henderson  */
4477d8b28b8SRichard Henderson static int arm_gdb_get_m_secextreg(CPUARMState *env, GByteArray *buf, int reg)
4487d8b28b8SRichard Henderson {
4497d8b28b8SRichard Henderson     return m_sysreg_get(env, buf, reg >> 1, reg & 1);
4507d8b28b8SRichard Henderson }
4517d8b28b8SRichard Henderson 
4527d8b28b8SRichard Henderson static int arm_gdb_set_m_secextreg(CPUARMState *env, uint8_t *buf, int reg)
4537d8b28b8SRichard Henderson {
4547d8b28b8SRichard Henderson     return 0; /* TODO */
4557d8b28b8SRichard Henderson }
4567d8b28b8SRichard Henderson 
4577d8b28b8SRichard Henderson static int arm_gen_dynamic_m_secextreg_xml(CPUState *cs, int orig_base_reg)
4587d8b28b8SRichard Henderson {
4597d8b28b8SRichard Henderson     ARMCPU *cpu = ARM_CPU(cs);
4607d8b28b8SRichard Henderson     GString *s = g_string_new(NULL);
4617d8b28b8SRichard Henderson     int base_reg = orig_base_reg;
4627d8b28b8SRichard Henderson     int i;
4637d8b28b8SRichard Henderson 
4647d8b28b8SRichard Henderson     g_string_printf(s, "<?xml version=\"1.0\"?>");
4657d8b28b8SRichard Henderson     g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">");
4667d8b28b8SRichard Henderson     g_string_append_printf(s, "<feature name=\"org.gnu.gdb.arm.secext\">\n");
4677d8b28b8SRichard Henderson 
4687d8b28b8SRichard Henderson     for (i = 0; i < ARRAY_SIZE(m_sysreg_def); i++) {
4697d8b28b8SRichard Henderson         g_string_append_printf(s,
4707d8b28b8SRichard Henderson             "<reg name=\"%s_ns\" bitsize=\"32\" regnum=\"%d\"/>\n",
4717d8b28b8SRichard Henderson             m_sysreg_def[i].name, base_reg++);
4727d8b28b8SRichard Henderson         g_string_append_printf(s,
4737d8b28b8SRichard Henderson             "<reg name=\"%s_s\" bitsize=\"32\" regnum=\"%d\"/>\n",
4747d8b28b8SRichard Henderson             m_sysreg_def[i].name, base_reg++);
4757d8b28b8SRichard Henderson     }
4767d8b28b8SRichard Henderson 
4777d8b28b8SRichard Henderson     g_string_append_printf(s, "</feature>");
4787d8b28b8SRichard Henderson     cpu->dyn_m_secextreg_xml.desc = g_string_free(s, false);
4797d8b28b8SRichard Henderson     cpu->dyn_m_secextreg_xml.num = base_reg - orig_base_reg;
4807d8b28b8SRichard Henderson 
4817d8b28b8SRichard Henderson     return cpu->dyn_m_secextreg_xml.num;
4827d8b28b8SRichard Henderson }
4837d8b28b8SRichard Henderson #endif
4847d8b28b8SRichard Henderson 
485200bf5b7SAbdallah Bouassida const char *arm_gdb_get_dynamic_xml(CPUState *cs, const char *xmlname)
486200bf5b7SAbdallah Bouassida {
487200bf5b7SAbdallah Bouassida     ARMCPU *cpu = ARM_CPU(cs);
488200bf5b7SAbdallah Bouassida 
489200bf5b7SAbdallah Bouassida     if (strcmp(xmlname, "system-registers.xml") == 0) {
490448d4d14SAlex Bennée         return cpu->dyn_sysreg_xml.desc;
491d12379c5SAlex Bennée     } else if (strcmp(xmlname, "sve-registers.xml") == 0) {
492d12379c5SAlex Bennée         return cpu->dyn_svereg_xml.desc;
4937d8b28b8SRichard Henderson     } else if (strcmp(xmlname, "arm-m-system.xml") == 0) {
4947d8b28b8SRichard Henderson         return cpu->dyn_m_systemreg_xml.desc;
4957d8b28b8SRichard Henderson #ifndef CONFIG_USER_ONLY
4967d8b28b8SRichard Henderson     } else if (strcmp(xmlname, "arm-m-secext.xml") == 0) {
4977d8b28b8SRichard Henderson         return cpu->dyn_m_secextreg_xml.desc;
4987d8b28b8SRichard Henderson #endif
499200bf5b7SAbdallah Bouassida     }
500200bf5b7SAbdallah Bouassida     return NULL;
501200bf5b7SAbdallah Bouassida }
50289f4f20eSPeter Maydell 
50389f4f20eSPeter Maydell void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu)
50489f4f20eSPeter Maydell {
50589f4f20eSPeter Maydell     CPUState *cs = CPU(cpu);
50689f4f20eSPeter Maydell     CPUARMState *env = &cpu->env;
50789f4f20eSPeter Maydell 
50889f4f20eSPeter Maydell     if (arm_feature(env, ARM_FEATURE_AARCH64)) {
50989f4f20eSPeter Maydell         /*
51089f4f20eSPeter Maydell          * The lower part of each SVE register aliases to the FPU
51189f4f20eSPeter Maydell          * registers so we don't need to include both.
51289f4f20eSPeter Maydell          */
51389f4f20eSPeter Maydell #ifdef TARGET_AARCH64
51489f4f20eSPeter Maydell         if (isar_feature_aa64_sve(&cpu->isar)) {
515963a6b91SRichard Henderson             int nreg = arm_gen_dynamic_svereg_xml(cs, cs->gdb_num_regs);
516963a6b91SRichard Henderson             gdb_register_coprocessor(cs, aarch64_gdb_get_sve_reg,
517963a6b91SRichard Henderson                                      aarch64_gdb_set_sve_reg, nreg,
51889f4f20eSPeter Maydell                                      "sve-registers.xml", 0);
51989f4f20eSPeter Maydell         } else {
520963a6b91SRichard Henderson             gdb_register_coprocessor(cs, aarch64_gdb_get_fpu_reg,
521963a6b91SRichard Henderson                                      aarch64_gdb_set_fpu_reg,
52289f4f20eSPeter Maydell                                      34, "aarch64-fpu.xml", 0);
52389f4f20eSPeter Maydell         }
5245787d17aSPeter Maydell #if 0
5255787d17aSPeter Maydell         /*
5265787d17aSPeter Maydell          * GDB versions 9 through 12 have a bug which means they will
5275787d17aSPeter Maydell          * crash if they see this XML from QEMU; disable it for the 8.0
5285787d17aSPeter Maydell          * release, pending a better solution.
5295787d17aSPeter Maydell          */
530e995d5ccSRichard Henderson         if (isar_feature_aa64_pauth(&cpu->isar)) {
531e995d5ccSRichard Henderson             gdb_register_coprocessor(cs, aarch64_gdb_get_pauth_reg,
532e995d5ccSRichard Henderson                                      aarch64_gdb_set_pauth_reg,
533e995d5ccSRichard Henderson                                      4, "aarch64-pauth.xml", 0);
534e995d5ccSRichard Henderson         }
53589f4f20eSPeter Maydell #endif
5365787d17aSPeter Maydell #endif
537b355f08aSPeter Maydell     } else {
538b355f08aSPeter Maydell         if (arm_feature(env, ARM_FEATURE_NEON)) {
53989f4f20eSPeter Maydell             gdb_register_coprocessor(cs, vfp_gdb_get_reg, vfp_gdb_set_reg,
540b355f08aSPeter Maydell                                      49, "arm-neon.xml", 0);
54189f4f20eSPeter Maydell         } else if (cpu_isar_feature(aa32_simd_r32, cpu)) {
54289f4f20eSPeter Maydell             gdb_register_coprocessor(cs, vfp_gdb_get_reg, vfp_gdb_set_reg,
543b355f08aSPeter Maydell                                      33, "arm-vfp3.xml", 0);
54489f4f20eSPeter Maydell         } else if (cpu_isar_feature(aa32_vfp_simd, cpu)) {
54589f4f20eSPeter Maydell             gdb_register_coprocessor(cs, vfp_gdb_get_reg, vfp_gdb_set_reg,
546b355f08aSPeter Maydell                                      17, "arm-vfp.xml", 0);
547b355f08aSPeter Maydell         }
548b355f08aSPeter Maydell         if (!arm_feature(env, ARM_FEATURE_M)) {
549b355f08aSPeter Maydell             /*
550b355f08aSPeter Maydell              * A and R profile have FP sysregs FPEXC and FPSID that we
551b355f08aSPeter Maydell              * expose to gdb.
552b355f08aSPeter Maydell              */
553b355f08aSPeter Maydell             gdb_register_coprocessor(cs, vfp_gdb_get_sysreg, vfp_gdb_set_sysreg,
554b355f08aSPeter Maydell                                      2, "arm-vfp-sysregs.xml", 0);
555b355f08aSPeter Maydell         }
55689f4f20eSPeter Maydell     }
557*46e3b237SPhilippe Mathieu-Daudé     if (cpu_isar_feature(aa32_mve, cpu) && tcg_enabled()) {
558dbd9e084SPeter Maydell         gdb_register_coprocessor(cs, mve_gdb_get_reg, mve_gdb_set_reg,
559dbd9e084SPeter Maydell                                  1, "arm-m-profile-mve.xml", 0);
560dbd9e084SPeter Maydell     }
56189f4f20eSPeter Maydell     gdb_register_coprocessor(cs, arm_gdb_get_sysreg, arm_gdb_set_sysreg,
56289f4f20eSPeter Maydell                              arm_gen_dynamic_sysreg_xml(cs, cs->gdb_num_regs),
56389f4f20eSPeter Maydell                              "system-registers.xml", 0);
56489f4f20eSPeter Maydell 
565*46e3b237SPhilippe Mathieu-Daudé     if (arm_feature(env, ARM_FEATURE_M) && tcg_enabled()) {
5667d8b28b8SRichard Henderson         gdb_register_coprocessor(cs,
5677d8b28b8SRichard Henderson             arm_gdb_get_m_systemreg, arm_gdb_set_m_systemreg,
5687d8b28b8SRichard Henderson             arm_gen_dynamic_m_systemreg_xml(cs, cs->gdb_num_regs),
5697d8b28b8SRichard Henderson             "arm-m-system.xml", 0);
5707d8b28b8SRichard Henderson #ifndef CONFIG_USER_ONLY
5717d8b28b8SRichard Henderson         if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
5727d8b28b8SRichard Henderson             gdb_register_coprocessor(cs,
5737d8b28b8SRichard Henderson                 arm_gdb_get_m_secextreg, arm_gdb_set_m_secextreg,
5747d8b28b8SRichard Henderson                 arm_gen_dynamic_m_secextreg_xml(cs, cs->gdb_num_regs),
5757d8b28b8SRichard Henderson                 "arm-m-secext.xml", 0);
5767d8b28b8SRichard Henderson         }
5777d8b28b8SRichard Henderson #endif
5787d8b28b8SRichard Henderson     }
57989f4f20eSPeter Maydell }
580