xref: /openbmc/qemu/target/arm/gdbstub.c (revision e8122a71)
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"
24f81198ceSGustavo Romero #include "gdbstub/commands.h"
2546e3b237SPhilippe Mathieu-Daudé #include "sysemu/tcg.h"
26cf7c6d10SRichard Henderson #include "internals.h"
275a534314SPeter Maydell #include "cpu-features.h"
28cf7c6d10SRichard Henderson #include "cpregs.h"
29fcf5ef2aSThomas Huth 
30690bd97bSAkihiko Odaki typedef struct RegisterSysregFeatureParam {
31200bf5b7SAbdallah Bouassida     CPUState *cs;
32690bd97bSAkihiko Odaki     GDBFeatureBuilder builder;
3332d6e32aSAlex Bennée     int n;
34690bd97bSAkihiko Odaki } RegisterSysregFeatureParam;
35200bf5b7SAbdallah Bouassida 
36fcf5ef2aSThomas Huth /* Old gdb always expect FPA registers.  Newer (xml-aware) gdb only expect
37fcf5ef2aSThomas Huth    whatever the target description contains.  Due to a historical mishap
38fcf5ef2aSThomas Huth    the FPA registers appear in between core integer regs and the CPSR.
39fcf5ef2aSThomas Huth    We hack round this by giving the FPA regs zero size when talking to a
40fcf5ef2aSThomas Huth    newer gdb.  */
41fcf5ef2aSThomas Huth 
arm_cpu_gdb_read_register(CPUState * cs,GByteArray * mem_buf,int n)42a010bdbeSAlex Bennée int arm_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
43fcf5ef2aSThomas Huth {
44fcf5ef2aSThomas Huth     ARMCPU *cpu = ARM_CPU(cs);
45fcf5ef2aSThomas Huth     CPUARMState *env = &cpu->env;
46fcf5ef2aSThomas Huth 
47fcf5ef2aSThomas Huth     if (n < 16) {
48fcf5ef2aSThomas Huth         /* Core integer register.  */
49fcf5ef2aSThomas Huth         return gdb_get_reg32(mem_buf, env->regs[n]);
50fcf5ef2aSThomas Huth     }
51dd2f7e29SAkihiko Odaki     if (n == 25) {
52c888f7e0SPeter Maydell         /* CPSR, or XPSR for M-profile */
53c888f7e0SPeter Maydell         if (arm_feature(env, ARM_FEATURE_M)) {
54c888f7e0SPeter Maydell             return gdb_get_reg32(mem_buf, xpsr_read(env));
55c888f7e0SPeter Maydell         } else {
56fcf5ef2aSThomas Huth             return gdb_get_reg32(mem_buf, cpsr_read(env));
57fcf5ef2aSThomas Huth         }
58c888f7e0SPeter Maydell     }
59fcf5ef2aSThomas Huth     /* Unknown register.  */
60fcf5ef2aSThomas Huth     return 0;
61fcf5ef2aSThomas Huth }
62fcf5ef2aSThomas Huth 
arm_cpu_gdb_write_register(CPUState * cs,uint8_t * mem_buf,int n)63fcf5ef2aSThomas Huth int arm_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
64fcf5ef2aSThomas Huth {
65fcf5ef2aSThomas Huth     ARMCPU *cpu = ARM_CPU(cs);
66fcf5ef2aSThomas Huth     CPUARMState *env = &cpu->env;
67fcf5ef2aSThomas Huth     uint32_t tmp;
68fcf5ef2aSThomas Huth 
69fcf5ef2aSThomas Huth     tmp = ldl_p(mem_buf);
70fcf5ef2aSThomas Huth 
717055fe4bSRichard Henderson     /*
727055fe4bSRichard Henderson      * Mask out low bits of PC to workaround gdb bugs.
737055fe4bSRichard Henderson      * This avoids an assert in thumb_tr_translate_insn, because it is
747055fe4bSRichard Henderson      * architecturally impossible to misalign the pc.
757055fe4bSRichard Henderson      * This will probably cause problems if we ever implement the
767055fe4bSRichard Henderson      * Jazelle DBX extensions.
777055fe4bSRichard Henderson      */
78fcf5ef2aSThomas Huth     if (n == 15) {
79fcf5ef2aSThomas Huth         tmp &= ~1;
80fcf5ef2aSThomas Huth     }
81fcf5ef2aSThomas Huth 
82fcf5ef2aSThomas Huth     if (n < 16) {
83fcf5ef2aSThomas Huth         /* Core integer register.  */
84888f470fSPeter Maydell         if (n == 13 && arm_feature(env, ARM_FEATURE_M)) {
85888f470fSPeter Maydell             /* M profile SP low bits are always 0 */
86888f470fSPeter Maydell             tmp &= ~3;
87888f470fSPeter Maydell         }
88fcf5ef2aSThomas Huth         env->regs[n] = tmp;
89fcf5ef2aSThomas Huth         return 4;
90fcf5ef2aSThomas Huth     }
91dd2f7e29SAkihiko Odaki     if (n == 25) {
92c888f7e0SPeter Maydell         /* CPSR, or XPSR for M-profile */
93c888f7e0SPeter Maydell         if (arm_feature(env, ARM_FEATURE_M)) {
94c888f7e0SPeter Maydell             /*
95c888f7e0SPeter Maydell              * Don't allow writing to XPSR.Exception as it can cause
96c888f7e0SPeter Maydell              * a transition into or out of handler mode (it's not
979323e79fSPeter Maydell              * writable via the MSR insn so this is a reasonable
98c888f7e0SPeter Maydell              * restriction). Other fields are safe to update.
99c888f7e0SPeter Maydell              */
100c888f7e0SPeter Maydell             xpsr_write(env, tmp, ~XPSR_EXCP);
101c888f7e0SPeter Maydell         } else {
102fcf5ef2aSThomas Huth             cpsr_write(env, tmp, 0xffffffff, CPSRWriteByGDBStub);
103c888f7e0SPeter Maydell         }
104fcf5ef2aSThomas Huth         return 4;
105fcf5ef2aSThomas Huth     }
106fcf5ef2aSThomas Huth     /* Unknown register.  */
107fcf5ef2aSThomas Huth     return 0;
108fcf5ef2aSThomas Huth }
109200bf5b7SAbdallah Bouassida 
vfp_gdb_get_reg(CPUState * cs,GByteArray * buf,int reg)11066260159SAkihiko Odaki static int vfp_gdb_get_reg(CPUState *cs, GByteArray *buf, int reg)
11189f4f20eSPeter Maydell {
11266260159SAkihiko Odaki     ARMCPU *cpu = ARM_CPU(cs);
11366260159SAkihiko Odaki     CPUARMState *env = &cpu->env;
11489f4f20eSPeter Maydell     int nregs = cpu_isar_feature(aa32_simd_r32, cpu) ? 32 : 16;
11589f4f20eSPeter Maydell 
11689f4f20eSPeter Maydell     /* VFP data registers are always little-endian.  */
11789f4f20eSPeter Maydell     if (reg < nregs) {
11889f4f20eSPeter Maydell         return gdb_get_reg64(buf, *aa32_vfp_dreg(env, reg));
11989f4f20eSPeter Maydell     }
12089f4f20eSPeter Maydell     if (arm_feature(env, ARM_FEATURE_NEON)) {
12189f4f20eSPeter Maydell         /* Aliases for Q regs.  */
12289f4f20eSPeter Maydell         nregs += 16;
12389f4f20eSPeter Maydell         if (reg < nregs) {
12489f4f20eSPeter Maydell             uint64_t *q = aa32_vfp_qreg(env, reg - 32);
12589f4f20eSPeter Maydell             return gdb_get_reg128(buf, q[0], q[1]);
12689f4f20eSPeter Maydell         }
12789f4f20eSPeter Maydell     }
12889f4f20eSPeter Maydell     switch (reg - nregs) {
12989f4f20eSPeter Maydell     case 0:
13089f4f20eSPeter Maydell         return gdb_get_reg32(buf, vfp_get_fpscr(env));
13189f4f20eSPeter Maydell     }
13289f4f20eSPeter Maydell     return 0;
13389f4f20eSPeter Maydell }
13489f4f20eSPeter Maydell 
vfp_gdb_set_reg(CPUState * cs,uint8_t * buf,int reg)13566260159SAkihiko Odaki static int vfp_gdb_set_reg(CPUState *cs, uint8_t *buf, int reg)
13689f4f20eSPeter Maydell {
13766260159SAkihiko Odaki     ARMCPU *cpu = ARM_CPU(cs);
13866260159SAkihiko Odaki     CPUARMState *env = &cpu->env;
13989f4f20eSPeter Maydell     int nregs = cpu_isar_feature(aa32_simd_r32, cpu) ? 32 : 16;
14089f4f20eSPeter Maydell 
14189f4f20eSPeter Maydell     if (reg < nregs) {
14289f4f20eSPeter Maydell         *aa32_vfp_dreg(env, reg) = ldq_le_p(buf);
14389f4f20eSPeter Maydell         return 8;
14489f4f20eSPeter Maydell     }
14589f4f20eSPeter Maydell     if (arm_feature(env, ARM_FEATURE_NEON)) {
14689f4f20eSPeter Maydell         nregs += 16;
14789f4f20eSPeter Maydell         if (reg < nregs) {
14889f4f20eSPeter Maydell             uint64_t *q = aa32_vfp_qreg(env, reg - 32);
14989f4f20eSPeter Maydell             q[0] = ldq_le_p(buf);
15089f4f20eSPeter Maydell             q[1] = ldq_le_p(buf + 8);
15189f4f20eSPeter Maydell             return 16;
15289f4f20eSPeter Maydell         }
15389f4f20eSPeter Maydell     }
15489f4f20eSPeter Maydell     switch (reg - nregs) {
15589f4f20eSPeter Maydell     case 0:
156b355f08aSPeter Maydell         vfp_set_fpscr(env, ldl_p(buf));
157b355f08aSPeter Maydell         return 4;
158b355f08aSPeter Maydell     }
159b355f08aSPeter Maydell     return 0;
160b355f08aSPeter Maydell }
161b355f08aSPeter Maydell 
vfp_gdb_get_sysreg(CPUState * cs,GByteArray * buf,int reg)16266260159SAkihiko Odaki static int vfp_gdb_get_sysreg(CPUState *cs, GByteArray *buf, int reg)
163b355f08aSPeter Maydell {
16466260159SAkihiko Odaki     ARMCPU *cpu = ARM_CPU(cs);
16566260159SAkihiko Odaki     CPUARMState *env = &cpu->env;
16666260159SAkihiko Odaki 
167b355f08aSPeter Maydell     switch (reg) {
168b355f08aSPeter Maydell     case 0:
169b355f08aSPeter Maydell         return gdb_get_reg32(buf, env->vfp.xregs[ARM_VFP_FPSID]);
170b355f08aSPeter Maydell     case 1:
171b355f08aSPeter Maydell         return gdb_get_reg32(buf, env->vfp.xregs[ARM_VFP_FPEXC]);
172b355f08aSPeter Maydell     }
173b355f08aSPeter Maydell     return 0;
174b355f08aSPeter Maydell }
175b355f08aSPeter Maydell 
vfp_gdb_set_sysreg(CPUState * cs,uint8_t * buf,int reg)17666260159SAkihiko Odaki static int vfp_gdb_set_sysreg(CPUState *cs, uint8_t *buf, int reg)
177b355f08aSPeter Maydell {
17866260159SAkihiko Odaki     ARMCPU *cpu = ARM_CPU(cs);
17966260159SAkihiko Odaki     CPUARMState *env = &cpu->env;
18066260159SAkihiko Odaki 
181b355f08aSPeter Maydell     switch (reg) {
182b355f08aSPeter Maydell     case 0:
18389f4f20eSPeter Maydell         env->vfp.xregs[ARM_VFP_FPSID] = ldl_p(buf);
18489f4f20eSPeter Maydell         return 4;
18589f4f20eSPeter Maydell     case 1:
18689f4f20eSPeter Maydell         env->vfp.xregs[ARM_VFP_FPEXC] = ldl_p(buf) & (1 << 30);
18789f4f20eSPeter Maydell         return 4;
18889f4f20eSPeter Maydell     }
18989f4f20eSPeter Maydell     return 0;
19089f4f20eSPeter Maydell }
19189f4f20eSPeter Maydell 
mve_gdb_get_reg(CPUState * cs,GByteArray * buf,int reg)19266260159SAkihiko Odaki static int mve_gdb_get_reg(CPUState *cs, GByteArray *buf, int reg)
193dbd9e084SPeter Maydell {
19466260159SAkihiko Odaki     ARMCPU *cpu = ARM_CPU(cs);
19566260159SAkihiko Odaki     CPUARMState *env = &cpu->env;
19666260159SAkihiko Odaki 
197dbd9e084SPeter Maydell     switch (reg) {
198dbd9e084SPeter Maydell     case 0:
199dbd9e084SPeter Maydell         return gdb_get_reg32(buf, env->v7m.vpr);
200dbd9e084SPeter Maydell     default:
201dbd9e084SPeter Maydell         return 0;
202dbd9e084SPeter Maydell     }
203dbd9e084SPeter Maydell }
204dbd9e084SPeter Maydell 
mve_gdb_set_reg(CPUState * cs,uint8_t * buf,int reg)20566260159SAkihiko Odaki static int mve_gdb_set_reg(CPUState *cs, uint8_t *buf, int reg)
206dbd9e084SPeter Maydell {
20766260159SAkihiko Odaki     ARMCPU *cpu = ARM_CPU(cs);
20866260159SAkihiko Odaki     CPUARMState *env = &cpu->env;
20966260159SAkihiko Odaki 
210dbd9e084SPeter Maydell     switch (reg) {
211dbd9e084SPeter Maydell     case 0:
212dbd9e084SPeter Maydell         env->v7m.vpr = ldl_p(buf);
213dbd9e084SPeter Maydell         return 4;
214dbd9e084SPeter Maydell     default:
215dbd9e084SPeter Maydell         return 0;
216dbd9e084SPeter Maydell     }
217dbd9e084SPeter Maydell }
218dbd9e084SPeter Maydell 
21989f4f20eSPeter Maydell /**
22089f4f20eSPeter Maydell  * arm_get/set_gdb_*: get/set a gdb register
22189f4f20eSPeter Maydell  * @env: the CPU state
22289f4f20eSPeter Maydell  * @buf: a buffer to copy to/from
22389f4f20eSPeter Maydell  * @reg: register number (offset from start of group)
22489f4f20eSPeter Maydell  *
22589f4f20eSPeter Maydell  * We return the number of bytes copied
22689f4f20eSPeter Maydell  */
22789f4f20eSPeter Maydell 
arm_gdb_get_sysreg(CPUState * cs,GByteArray * buf,int reg)22866260159SAkihiko Odaki static int arm_gdb_get_sysreg(CPUState *cs, GByteArray *buf, int reg)
22989f4f20eSPeter Maydell {
23066260159SAkihiko Odaki     ARMCPU *cpu = ARM_CPU(cs);
23166260159SAkihiko Odaki     CPUARMState *env = &cpu->env;
23289f4f20eSPeter Maydell     const ARMCPRegInfo *ri;
23389f4f20eSPeter Maydell     uint32_t key;
23489f4f20eSPeter Maydell 
235690bd97bSAkihiko Odaki     key = cpu->dyn_sysreg_feature.data.cpregs.keys[reg];
23689f4f20eSPeter Maydell     ri = get_arm_cp_reginfo(cpu->cp_regs, key);
23789f4f20eSPeter Maydell     if (ri) {
23889f4f20eSPeter Maydell         if (cpreg_field_is_64bit(ri)) {
23989f4f20eSPeter Maydell             return gdb_get_reg64(buf, (uint64_t)read_raw_cp_reg(env, ri));
24089f4f20eSPeter Maydell         } else {
24189f4f20eSPeter Maydell             return gdb_get_reg32(buf, (uint32_t)read_raw_cp_reg(env, ri));
24289f4f20eSPeter Maydell         }
24389f4f20eSPeter Maydell     }
24489f4f20eSPeter Maydell     return 0;
24589f4f20eSPeter Maydell }
24689f4f20eSPeter Maydell 
arm_gdb_set_sysreg(CPUState * cs,uint8_t * buf,int reg)24766260159SAkihiko Odaki static int arm_gdb_set_sysreg(CPUState *cs, uint8_t *buf, int reg)
24889f4f20eSPeter Maydell {
24989f4f20eSPeter Maydell     return 0;
25089f4f20eSPeter Maydell }
25189f4f20eSPeter Maydell 
arm_gen_one_feature_sysreg(GDBFeatureBuilder * builder,DynamicGDBFeatureInfo * dyn_feature,ARMCPRegInfo * ri,uint32_t ri_key,int bitsize,int n)252690bd97bSAkihiko Odaki static void arm_gen_one_feature_sysreg(GDBFeatureBuilder *builder,
253690bd97bSAkihiko Odaki                                        DynamicGDBFeatureInfo *dyn_feature,
254200bf5b7SAbdallah Bouassida                                        ARMCPRegInfo *ri, uint32_t ri_key,
255690bd97bSAkihiko Odaki                                        int bitsize, int n)
256200bf5b7SAbdallah Bouassida {
257690bd97bSAkihiko Odaki     gdb_feature_builder_append_reg(builder, ri->name, bitsize, n,
258690bd97bSAkihiko Odaki                                    "int", "cp_regs");
259690bd97bSAkihiko Odaki 
260690bd97bSAkihiko Odaki     dyn_feature->data.cpregs.keys[n] = ri_key;
261200bf5b7SAbdallah Bouassida }
262200bf5b7SAbdallah Bouassida 
arm_register_sysreg_for_feature(gpointer key,gpointer value,gpointer p)263690bd97bSAkihiko Odaki static void arm_register_sysreg_for_feature(gpointer key, gpointer value,
264200bf5b7SAbdallah Bouassida                                             gpointer p)
265200bf5b7SAbdallah Bouassida {
2665860362dSRichard Henderson     uint32_t ri_key = (uintptr_t)key;
267200bf5b7SAbdallah Bouassida     ARMCPRegInfo *ri = value;
268690bd97bSAkihiko Odaki     RegisterSysregFeatureParam *param = p;
269200bf5b7SAbdallah Bouassida     ARMCPU *cpu = ARM_CPU(param->cs);
270200bf5b7SAbdallah Bouassida     CPUARMState *env = &cpu->env;
271690bd97bSAkihiko Odaki     DynamicGDBFeatureInfo *dyn_feature = &cpu->dyn_sysreg_feature;
272200bf5b7SAbdallah Bouassida 
273200bf5b7SAbdallah Bouassida     if (!(ri->type & (ARM_CP_NO_RAW | ARM_CP_NO_GDB))) {
274200bf5b7SAbdallah Bouassida         if (arm_feature(env, ARM_FEATURE_AARCH64)) {
275200bf5b7SAbdallah Bouassida             if (ri->state == ARM_CP_STATE_AA64) {
276690bd97bSAkihiko Odaki                 arm_gen_one_feature_sysreg(&param->builder, dyn_feature,
277690bd97bSAkihiko Odaki                                            ri, ri_key, 64, param->n++);
278200bf5b7SAbdallah Bouassida             }
279200bf5b7SAbdallah Bouassida         } else {
280200bf5b7SAbdallah Bouassida             if (ri->state == ARM_CP_STATE_AA32) {
281200bf5b7SAbdallah Bouassida                 if (!arm_feature(env, ARM_FEATURE_EL3) &&
282200bf5b7SAbdallah Bouassida                     (ri->secure & ARM_CP_SECSTATE_S)) {
283200bf5b7SAbdallah Bouassida                     return;
284200bf5b7SAbdallah Bouassida                 }
285200bf5b7SAbdallah Bouassida                 if (ri->type & ARM_CP_64BIT) {
286690bd97bSAkihiko Odaki                     arm_gen_one_feature_sysreg(&param->builder, dyn_feature,
287690bd97bSAkihiko Odaki                                                ri, ri_key, 64, param->n++);
288200bf5b7SAbdallah Bouassida                 } else {
289690bd97bSAkihiko Odaki                     arm_gen_one_feature_sysreg(&param->builder, dyn_feature,
290690bd97bSAkihiko Odaki                                                ri, ri_key, 32, param->n++);
291200bf5b7SAbdallah Bouassida                 }
292200bf5b7SAbdallah Bouassida             }
293200bf5b7SAbdallah Bouassida         }
294200bf5b7SAbdallah Bouassida     }
295200bf5b7SAbdallah Bouassida }
296200bf5b7SAbdallah Bouassida 
arm_gen_dynamic_sysreg_feature(CPUState * cs,int base_reg)297690bd97bSAkihiko Odaki static GDBFeature *arm_gen_dynamic_sysreg_feature(CPUState *cs, int base_reg)
298200bf5b7SAbdallah Bouassida {
299200bf5b7SAbdallah Bouassida     ARMCPU *cpu = ARM_CPU(cs);
300690bd97bSAkihiko Odaki     RegisterSysregFeatureParam param = {cs};
301690bd97bSAkihiko Odaki     gsize num_regs = g_hash_table_size(cpu->cp_regs);
302200bf5b7SAbdallah Bouassida 
303690bd97bSAkihiko Odaki     gdb_feature_builder_init(&param.builder,
304690bd97bSAkihiko Odaki                              &cpu->dyn_sysreg_feature.desc,
305690bd97bSAkihiko Odaki                              "org.qemu.gdb.arm.sys.regs",
306690bd97bSAkihiko Odaki                              "system-registers.xml",
307690bd97bSAkihiko Odaki                              base_reg);
308690bd97bSAkihiko Odaki     cpu->dyn_sysreg_feature.data.cpregs.keys = g_new(uint32_t, num_regs);
309690bd97bSAkihiko Odaki     g_hash_table_foreach(cpu->cp_regs, arm_register_sysreg_for_feature, &param);
310690bd97bSAkihiko Odaki     gdb_feature_builder_end(&param.builder);
311690bd97bSAkihiko Odaki     return &cpu->dyn_sysreg_feature.desc;
312200bf5b7SAbdallah Bouassida }
313200bf5b7SAbdallah Bouassida 
314893ca916SFabiano Rosas #ifdef CONFIG_TCG
3157d8b28b8SRichard Henderson typedef enum {
3167d8b28b8SRichard Henderson     M_SYSREG_MSP,
3177d8b28b8SRichard Henderson     M_SYSREG_PSP,
3187d8b28b8SRichard Henderson     M_SYSREG_PRIMASK,
3197d8b28b8SRichard Henderson     M_SYSREG_CONTROL,
3207d8b28b8SRichard Henderson     M_SYSREG_BASEPRI,
3217d8b28b8SRichard Henderson     M_SYSREG_FAULTMASK,
3227d8b28b8SRichard Henderson     M_SYSREG_MSPLIM,
3237d8b28b8SRichard Henderson     M_SYSREG_PSPLIM,
3247d8b28b8SRichard Henderson } MProfileSysreg;
3257d8b28b8SRichard Henderson 
3267d8b28b8SRichard Henderson static const struct {
3277d8b28b8SRichard Henderson     const char *name;
3287d8b28b8SRichard Henderson     int feature;
3297d8b28b8SRichard Henderson } m_sysreg_def[] = {
3307d8b28b8SRichard Henderson     [M_SYSREG_MSP] = { "msp", ARM_FEATURE_M },
3317d8b28b8SRichard Henderson     [M_SYSREG_PSP] = { "psp", ARM_FEATURE_M },
3327d8b28b8SRichard Henderson     [M_SYSREG_PRIMASK] = { "primask", ARM_FEATURE_M },
3337d8b28b8SRichard Henderson     [M_SYSREG_CONTROL] = { "control", ARM_FEATURE_M },
3347d8b28b8SRichard Henderson     [M_SYSREG_BASEPRI] = { "basepri", ARM_FEATURE_M_MAIN },
3357d8b28b8SRichard Henderson     [M_SYSREG_FAULTMASK] = { "faultmask", ARM_FEATURE_M_MAIN },
3367d8b28b8SRichard Henderson     [M_SYSREG_MSPLIM] = { "msplim", ARM_FEATURE_V8 },
3377d8b28b8SRichard Henderson     [M_SYSREG_PSPLIM] = { "psplim", ARM_FEATURE_V8 },
3387d8b28b8SRichard Henderson };
3397d8b28b8SRichard Henderson 
m_sysreg_ptr(CPUARMState * env,MProfileSysreg reg,bool sec)3407d8b28b8SRichard Henderson static uint32_t *m_sysreg_ptr(CPUARMState *env, MProfileSysreg reg, bool sec)
3417d8b28b8SRichard Henderson {
3427d8b28b8SRichard Henderson     uint32_t *ptr;
3437d8b28b8SRichard Henderson 
3447d8b28b8SRichard Henderson     switch (reg) {
3457d8b28b8SRichard Henderson     case M_SYSREG_MSP:
3467d8b28b8SRichard Henderson         ptr = arm_v7m_get_sp_ptr(env, sec, false, true);
3477d8b28b8SRichard Henderson         break;
3487d8b28b8SRichard Henderson     case M_SYSREG_PSP:
3497d8b28b8SRichard Henderson         ptr = arm_v7m_get_sp_ptr(env, sec, true, true);
3507d8b28b8SRichard Henderson         break;
3517d8b28b8SRichard Henderson     case M_SYSREG_MSPLIM:
3527d8b28b8SRichard Henderson         ptr = &env->v7m.msplim[sec];
3537d8b28b8SRichard Henderson         break;
3547d8b28b8SRichard Henderson     case M_SYSREG_PSPLIM:
3557d8b28b8SRichard Henderson         ptr = &env->v7m.psplim[sec];
3567d8b28b8SRichard Henderson         break;
3577d8b28b8SRichard Henderson     case M_SYSREG_PRIMASK:
3587d8b28b8SRichard Henderson         ptr = &env->v7m.primask[sec];
3597d8b28b8SRichard Henderson         break;
3607d8b28b8SRichard Henderson     case M_SYSREG_BASEPRI:
3617d8b28b8SRichard Henderson         ptr = &env->v7m.basepri[sec];
3627d8b28b8SRichard Henderson         break;
3637d8b28b8SRichard Henderson     case M_SYSREG_FAULTMASK:
3647d8b28b8SRichard Henderson         ptr = &env->v7m.faultmask[sec];
3657d8b28b8SRichard Henderson         break;
3667d8b28b8SRichard Henderson     case M_SYSREG_CONTROL:
3677d8b28b8SRichard Henderson         ptr = &env->v7m.control[sec];
3687d8b28b8SRichard Henderson         break;
3697d8b28b8SRichard Henderson     default:
3707d8b28b8SRichard Henderson         return NULL;
3717d8b28b8SRichard Henderson     }
3727d8b28b8SRichard Henderson     return arm_feature(env, m_sysreg_def[reg].feature) ? ptr : NULL;
3737d8b28b8SRichard Henderson }
3747d8b28b8SRichard Henderson 
m_sysreg_get(CPUARMState * env,GByteArray * buf,MProfileSysreg reg,bool secure)3757d8b28b8SRichard Henderson static int m_sysreg_get(CPUARMState *env, GByteArray *buf,
3767d8b28b8SRichard Henderson                         MProfileSysreg reg, bool secure)
3777d8b28b8SRichard Henderson {
3787d8b28b8SRichard Henderson     uint32_t *ptr = m_sysreg_ptr(env, reg, secure);
3797d8b28b8SRichard Henderson 
3807d8b28b8SRichard Henderson     if (ptr == NULL) {
3817d8b28b8SRichard Henderson         return 0;
3827d8b28b8SRichard Henderson     }
3837d8b28b8SRichard Henderson     return gdb_get_reg32(buf, *ptr);
3847d8b28b8SRichard Henderson }
3857d8b28b8SRichard Henderson 
arm_gdb_get_m_systemreg(CPUState * cs,GByteArray * buf,int reg)38666260159SAkihiko Odaki static int arm_gdb_get_m_systemreg(CPUState *cs, GByteArray *buf, int reg)
3877d8b28b8SRichard Henderson {
38866260159SAkihiko Odaki     ARMCPU *cpu = ARM_CPU(cs);
38966260159SAkihiko Odaki     CPUARMState *env = &cpu->env;
39066260159SAkihiko Odaki 
3917d8b28b8SRichard Henderson     /*
3927d8b28b8SRichard Henderson      * Here, we emulate MRS instruction, where CONTROL has a mix of
3937d8b28b8SRichard Henderson      * banked and non-banked bits.
3947d8b28b8SRichard Henderson      */
3957d8b28b8SRichard Henderson     if (reg == M_SYSREG_CONTROL) {
3967d8b28b8SRichard Henderson         return gdb_get_reg32(buf, arm_v7m_mrs_control(env, env->v7m.secure));
3977d8b28b8SRichard Henderson     }
3987d8b28b8SRichard Henderson     return m_sysreg_get(env, buf, reg, env->v7m.secure);
3997d8b28b8SRichard Henderson }
4007d8b28b8SRichard Henderson 
arm_gdb_set_m_systemreg(CPUState * cs,uint8_t * buf,int reg)40166260159SAkihiko Odaki static int arm_gdb_set_m_systemreg(CPUState *cs, uint8_t *buf, int reg)
4027d8b28b8SRichard Henderson {
4037d8b28b8SRichard Henderson     return 0; /* TODO */
4047d8b28b8SRichard Henderson }
4057d8b28b8SRichard Henderson 
arm_gen_dynamic_m_systemreg_feature(CPUState * cs,int base_reg)406690bd97bSAkihiko Odaki static GDBFeature *arm_gen_dynamic_m_systemreg_feature(CPUState *cs,
407690bd97bSAkihiko Odaki                                                        int base_reg)
4087d8b28b8SRichard Henderson {
4097d8b28b8SRichard Henderson     ARMCPU *cpu = ARM_CPU(cs);
4107d8b28b8SRichard Henderson     CPUARMState *env = &cpu->env;
411690bd97bSAkihiko Odaki     GDBFeatureBuilder builder;
412690bd97bSAkihiko Odaki     int reg = 0;
4137d8b28b8SRichard Henderson     int i;
4147d8b28b8SRichard Henderson 
415690bd97bSAkihiko Odaki     gdb_feature_builder_init(&builder, &cpu->dyn_m_systemreg_feature.desc,
416690bd97bSAkihiko Odaki                              "org.gnu.gdb.arm.m-system", "arm-m-system.xml",
417690bd97bSAkihiko Odaki                              base_reg);
4187d8b28b8SRichard Henderson 
4197d8b28b8SRichard Henderson     for (i = 0; i < ARRAY_SIZE(m_sysreg_def); i++) {
4207d8b28b8SRichard Henderson         if (arm_feature(env, m_sysreg_def[i].feature)) {
421690bd97bSAkihiko Odaki             gdb_feature_builder_append_reg(&builder, m_sysreg_def[i].name, 32,
422690bd97bSAkihiko Odaki                                            reg++, "int", NULL);
4237d8b28b8SRichard Henderson         }
4247d8b28b8SRichard Henderson     }
4257d8b28b8SRichard Henderson 
426690bd97bSAkihiko Odaki     gdb_feature_builder_end(&builder);
4277d8b28b8SRichard Henderson 
428690bd97bSAkihiko Odaki     return &cpu->dyn_m_systemreg_feature.desc;
4297d8b28b8SRichard Henderson }
4307d8b28b8SRichard Henderson 
4317d8b28b8SRichard Henderson #ifndef CONFIG_USER_ONLY
4327d8b28b8SRichard Henderson /*
4337d8b28b8SRichard Henderson  * For user-only, we see the non-secure registers via m_systemreg above.
4347d8b28b8SRichard Henderson  * For secext, encode the non-secure view as even and secure view as odd.
4357d8b28b8SRichard Henderson  */
arm_gdb_get_m_secextreg(CPUState * cs,GByteArray * buf,int reg)43666260159SAkihiko Odaki static int arm_gdb_get_m_secextreg(CPUState *cs, GByteArray *buf, int reg)
4377d8b28b8SRichard Henderson {
43866260159SAkihiko Odaki     ARMCPU *cpu = ARM_CPU(cs);
43966260159SAkihiko Odaki     CPUARMState *env = &cpu->env;
44066260159SAkihiko Odaki 
4417d8b28b8SRichard Henderson     return m_sysreg_get(env, buf, reg >> 1, reg & 1);
4427d8b28b8SRichard Henderson }
4437d8b28b8SRichard Henderson 
arm_gdb_set_m_secextreg(CPUState * cs,uint8_t * buf,int reg)44466260159SAkihiko Odaki static int arm_gdb_set_m_secextreg(CPUState *cs, uint8_t *buf, int reg)
4457d8b28b8SRichard Henderson {
4467d8b28b8SRichard Henderson     return 0; /* TODO */
4477d8b28b8SRichard Henderson }
4487d8b28b8SRichard Henderson 
arm_gen_dynamic_m_secextreg_feature(CPUState * cs,int base_reg)449690bd97bSAkihiko Odaki static GDBFeature *arm_gen_dynamic_m_secextreg_feature(CPUState *cs,
450690bd97bSAkihiko Odaki                                                        int base_reg)
4517d8b28b8SRichard Henderson {
4527d8b28b8SRichard Henderson     ARMCPU *cpu = ARM_CPU(cs);
453690bd97bSAkihiko Odaki     GDBFeatureBuilder builder;
454690bd97bSAkihiko Odaki     char *name;
455690bd97bSAkihiko Odaki     int reg = 0;
4567d8b28b8SRichard Henderson     int i;
4577d8b28b8SRichard Henderson 
458690bd97bSAkihiko Odaki     gdb_feature_builder_init(&builder, &cpu->dyn_m_secextreg_feature.desc,
459690bd97bSAkihiko Odaki                              "org.gnu.gdb.arm.secext", "arm-m-secext.xml",
460690bd97bSAkihiko Odaki                              base_reg);
4617d8b28b8SRichard Henderson 
4627d8b28b8SRichard Henderson     for (i = 0; i < ARRAY_SIZE(m_sysreg_def); i++) {
463690bd97bSAkihiko Odaki         name = g_strconcat(m_sysreg_def[i].name, "_ns", NULL);
464690bd97bSAkihiko Odaki         gdb_feature_builder_append_reg(&builder, name, 32, reg++,
465690bd97bSAkihiko Odaki                                        "int", NULL);
466690bd97bSAkihiko Odaki         name = g_strconcat(m_sysreg_def[i].name, "_s", NULL);
467690bd97bSAkihiko Odaki         gdb_feature_builder_append_reg(&builder, name, 32, reg++,
468690bd97bSAkihiko Odaki                                        "int", NULL);
4697d8b28b8SRichard Henderson     }
4707d8b28b8SRichard Henderson 
471690bd97bSAkihiko Odaki     gdb_feature_builder_end(&builder);
4727d8b28b8SRichard Henderson 
473690bd97bSAkihiko Odaki     return &cpu->dyn_m_secextreg_feature.desc;
4747d8b28b8SRichard Henderson }
4757d8b28b8SRichard Henderson #endif
476893ca916SFabiano Rosas #endif /* CONFIG_TCG */
4777d8b28b8SRichard Henderson 
arm_cpu_register_gdb_commands(ARMCPU * cpu)478f81198ceSGustavo Romero void arm_cpu_register_gdb_commands(ARMCPU *cpu)
479f81198ceSGustavo Romero {
480*e8122a71SAlex Bennée     g_autoptr(GPtrArray) query_table = g_ptr_array_new();
481*e8122a71SAlex Bennée     g_autoptr(GPtrArray) set_table = g_ptr_array_new();
482*e8122a71SAlex Bennée     g_autoptr(GString) qsupported_features = g_string_new(NULL);
483f81198ceSGustavo Romero 
484f81198ceSGustavo Romero     if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
485f81198ceSGustavo Romero     #ifdef TARGET_AARCH64
486f81198ceSGustavo Romero         aarch64_cpu_register_gdb_commands(cpu, qsupported_features, query_table,
487f81198ceSGustavo Romero                                           set_table);
488f81198ceSGustavo Romero     #endif
489f81198ceSGustavo Romero     }
490f81198ceSGustavo Romero 
491f81198ceSGustavo Romero     /* Set arch-specific handlers for 'q' commands. */
492f81198ceSGustavo Romero     if (query_table->len) {
493*e8122a71SAlex Bennée         gdb_extend_query_table(query_table);
494f81198ceSGustavo Romero     }
495f81198ceSGustavo Romero 
496f81198ceSGustavo Romero     /* Set arch-specific handlers for 'Q' commands. */
497f81198ceSGustavo Romero     if (set_table->len) {
498*e8122a71SAlex Bennée         gdb_extend_set_table(set_table);
499f81198ceSGustavo Romero     }
500f81198ceSGustavo Romero 
501f81198ceSGustavo Romero     /* Set arch-specific qSupported feature. */
502f81198ceSGustavo Romero     if (qsupported_features->len) {
503f81198ceSGustavo Romero         gdb_extend_qsupported_features(qsupported_features->str);
504f81198ceSGustavo Romero     }
505f81198ceSGustavo Romero }
506f81198ceSGustavo Romero 
arm_cpu_register_gdb_regs_for_features(ARMCPU * cpu)50789f4f20eSPeter Maydell void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu)
50889f4f20eSPeter Maydell {
50989f4f20eSPeter Maydell     CPUState *cs = CPU(cpu);
51089f4f20eSPeter Maydell     CPUARMState *env = &cpu->env;
51189f4f20eSPeter Maydell 
51289f4f20eSPeter Maydell     if (arm_feature(env, ARM_FEATURE_AARCH64)) {
51389f4f20eSPeter Maydell         /*
51489f4f20eSPeter Maydell          * The lower part of each SVE register aliases to the FPU
51589f4f20eSPeter Maydell          * registers so we don't need to include both.
51689f4f20eSPeter Maydell          */
51789f4f20eSPeter Maydell #ifdef TARGET_AARCH64
51889f4f20eSPeter Maydell         if (isar_feature_aa64_sve(&cpu->isar)) {
519ac1e8671SAkihiko Odaki             GDBFeature *feature = arm_gen_dynamic_svereg_feature(cs, cs->gdb_num_regs);
520963a6b91SRichard Henderson             gdb_register_coprocessor(cs, aarch64_gdb_get_sve_reg,
521ac1e8671SAkihiko Odaki                                      aarch64_gdb_set_sve_reg, feature, 0);
52289f4f20eSPeter Maydell         } else {
523963a6b91SRichard Henderson             gdb_register_coprocessor(cs, aarch64_gdb_get_fpu_reg,
524963a6b91SRichard Henderson                                      aarch64_gdb_set_fpu_reg,
525ac1e8671SAkihiko Odaki                                      gdb_find_static_feature("aarch64-fpu.xml"),
526ac1e8671SAkihiko Odaki                                      0);
52789f4f20eSPeter Maydell         }
5285787d17aSPeter Maydell         /*
5297bdd67a5SPeter Maydell          * Note that we report pauth information via the feature name
5307bdd67a5SPeter Maydell          * org.gnu.gdb.aarch64.pauth_v2, not org.gnu.gdb.aarch64.pauth.
5317bdd67a5SPeter Maydell          * GDB versions 9 through 12 have a bug where they will crash
5327bdd67a5SPeter Maydell          * if they see the latter XML from QEMU.
5335787d17aSPeter Maydell          */
534e995d5ccSRichard Henderson         if (isar_feature_aa64_pauth(&cpu->isar)) {
535e995d5ccSRichard Henderson             gdb_register_coprocessor(cs, aarch64_gdb_get_pauth_reg,
536e995d5ccSRichard Henderson                                      aarch64_gdb_set_pauth_reg,
537ac1e8671SAkihiko Odaki                                      gdb_find_static_feature("aarch64-pauth.xml"),
538ac1e8671SAkihiko Odaki                                      0);
539e995d5ccSRichard Henderson         }
540f81198ceSGustavo Romero 
541f81198ceSGustavo Romero #ifdef CONFIG_USER_ONLY
542f81198ceSGustavo Romero         /* Memory Tagging Extension (MTE) 'tag_ctl' pseudo-register. */
543f81198ceSGustavo Romero         if (cpu_isar_feature(aa64_mte, cpu)) {
544f81198ceSGustavo Romero             gdb_register_coprocessor(cs, aarch64_gdb_get_tag_ctl_reg,
545f81198ceSGustavo Romero                                      aarch64_gdb_set_tag_ctl_reg,
546f81198ceSGustavo Romero                                      gdb_find_static_feature("aarch64-mte.xml"),
547f81198ceSGustavo Romero                                      0);
548f81198ceSGustavo Romero         }
549f81198ceSGustavo Romero #endif
55089f4f20eSPeter Maydell #endif
551b355f08aSPeter Maydell     } else {
552b355f08aSPeter Maydell         if (arm_feature(env, ARM_FEATURE_NEON)) {
55389f4f20eSPeter Maydell             gdb_register_coprocessor(cs, vfp_gdb_get_reg, vfp_gdb_set_reg,
554ac1e8671SAkihiko Odaki                                      gdb_find_static_feature("arm-neon.xml"),
555ac1e8671SAkihiko Odaki                                      0);
55689f4f20eSPeter Maydell         } else if (cpu_isar_feature(aa32_simd_r32, cpu)) {
55789f4f20eSPeter Maydell             gdb_register_coprocessor(cs, vfp_gdb_get_reg, vfp_gdb_set_reg,
558ac1e8671SAkihiko Odaki                                      gdb_find_static_feature("arm-vfp3.xml"),
559ac1e8671SAkihiko Odaki                                      0);
56089f4f20eSPeter Maydell         } else if (cpu_isar_feature(aa32_vfp_simd, cpu)) {
56189f4f20eSPeter Maydell             gdb_register_coprocessor(cs, vfp_gdb_get_reg, vfp_gdb_set_reg,
562ac1e8671SAkihiko Odaki                                      gdb_find_static_feature("arm-vfp.xml"), 0);
563b355f08aSPeter Maydell         }
564b355f08aSPeter Maydell         if (!arm_feature(env, ARM_FEATURE_M)) {
565b355f08aSPeter Maydell             /*
566b355f08aSPeter Maydell              * A and R profile have FP sysregs FPEXC and FPSID that we
567b355f08aSPeter Maydell              * expose to gdb.
568b355f08aSPeter Maydell              */
569b355f08aSPeter Maydell             gdb_register_coprocessor(cs, vfp_gdb_get_sysreg, vfp_gdb_set_sysreg,
570ac1e8671SAkihiko Odaki                                      gdb_find_static_feature("arm-vfp-sysregs.xml"),
571ac1e8671SAkihiko Odaki                                      0);
572b355f08aSPeter Maydell         }
57389f4f20eSPeter Maydell     }
57446e3b237SPhilippe Mathieu-Daudé     if (cpu_isar_feature(aa32_mve, cpu) && tcg_enabled()) {
575dbd9e084SPeter Maydell         gdb_register_coprocessor(cs, mve_gdb_get_reg, mve_gdb_set_reg,
576ac1e8671SAkihiko Odaki                                  gdb_find_static_feature("arm-m-profile-mve.xml"),
577ac1e8671SAkihiko Odaki                                  0);
578dbd9e084SPeter Maydell     }
57989f4f20eSPeter Maydell     gdb_register_coprocessor(cs, arm_gdb_get_sysreg, arm_gdb_set_sysreg,
580ac1e8671SAkihiko Odaki                              arm_gen_dynamic_sysreg_feature(cs, cs->gdb_num_regs),
581ac1e8671SAkihiko Odaki                              0);
58289f4f20eSPeter Maydell 
583893ca916SFabiano Rosas #ifdef CONFIG_TCG
58446e3b237SPhilippe Mathieu-Daudé     if (arm_feature(env, ARM_FEATURE_M) && tcg_enabled()) {
5857d8b28b8SRichard Henderson         gdb_register_coprocessor(cs,
5867d8b28b8SRichard Henderson             arm_gdb_get_m_systemreg, arm_gdb_set_m_systemreg,
587ac1e8671SAkihiko Odaki             arm_gen_dynamic_m_systemreg_feature(cs, cs->gdb_num_regs), 0);
5887d8b28b8SRichard Henderson #ifndef CONFIG_USER_ONLY
5897d8b28b8SRichard Henderson         if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
5907d8b28b8SRichard Henderson             gdb_register_coprocessor(cs,
5917d8b28b8SRichard Henderson                 arm_gdb_get_m_secextreg, arm_gdb_set_m_secextreg,
592ac1e8671SAkihiko Odaki                 arm_gen_dynamic_m_secextreg_feature(cs, cs->gdb_num_regs), 0);
5937d8b28b8SRichard Henderson         }
5947d8b28b8SRichard Henderson #endif
5957d8b28b8SRichard Henderson     }
596893ca916SFabiano Rosas #endif /* CONFIG_TCG */
59789f4f20eSPeter Maydell }
598