xref: /openbmc/qemu/target/arm/gdbstub.c (revision 797920b952ea154a73049d171f5d5e3d6fb0bbea)
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"
23fcf5ef2aSThomas Huth 
24200bf5b7SAbdallah Bouassida typedef struct RegisterSysregXmlParam {
25200bf5b7SAbdallah Bouassida     CPUState *cs;
26200bf5b7SAbdallah Bouassida     GString *s;
2732d6e32aSAlex Bennée     int n;
28200bf5b7SAbdallah Bouassida } RegisterSysregXmlParam;
29200bf5b7SAbdallah Bouassida 
30fcf5ef2aSThomas Huth /* Old gdb always expect FPA registers.  Newer (xml-aware) gdb only expect
31fcf5ef2aSThomas Huth    whatever the target description contains.  Due to a historical mishap
32fcf5ef2aSThomas Huth    the FPA registers appear in between core integer regs and the CPSR.
33fcf5ef2aSThomas Huth    We hack round this by giving the FPA regs zero size when talking to a
34fcf5ef2aSThomas Huth    newer gdb.  */
35fcf5ef2aSThomas Huth 
36a010bdbeSAlex Bennée int arm_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
37fcf5ef2aSThomas Huth {
38fcf5ef2aSThomas Huth     ARMCPU *cpu = ARM_CPU(cs);
39fcf5ef2aSThomas Huth     CPUARMState *env = &cpu->env;
40fcf5ef2aSThomas Huth 
41fcf5ef2aSThomas Huth     if (n < 16) {
42fcf5ef2aSThomas Huth         /* Core integer register.  */
43fcf5ef2aSThomas Huth         return gdb_get_reg32(mem_buf, env->regs[n]);
44fcf5ef2aSThomas Huth     }
45fcf5ef2aSThomas Huth     if (n < 24) {
46fcf5ef2aSThomas Huth         /* FPA registers.  */
47fcf5ef2aSThomas Huth         if (gdb_has_xml) {
48fcf5ef2aSThomas Huth             return 0;
49fcf5ef2aSThomas Huth         }
507b8c1527SPhilippe Mathieu-Daudé         return gdb_get_zeroes(mem_buf, 12);
51fcf5ef2aSThomas Huth     }
52fcf5ef2aSThomas Huth     switch (n) {
53fcf5ef2aSThomas Huth     case 24:
54fcf5ef2aSThomas Huth         /* FPA status register.  */
55fcf5ef2aSThomas Huth         if (gdb_has_xml) {
56fcf5ef2aSThomas Huth             return 0;
57fcf5ef2aSThomas Huth         }
58fcf5ef2aSThomas Huth         return gdb_get_reg32(mem_buf, 0);
59fcf5ef2aSThomas Huth     case 25:
60c888f7e0SPeter Maydell         /* CPSR, or XPSR for M-profile */
61c888f7e0SPeter Maydell         if (arm_feature(env, ARM_FEATURE_M)) {
62c888f7e0SPeter Maydell             return gdb_get_reg32(mem_buf, xpsr_read(env));
63c888f7e0SPeter Maydell         } else {
64fcf5ef2aSThomas Huth             return gdb_get_reg32(mem_buf, cpsr_read(env));
65fcf5ef2aSThomas Huth         }
66c888f7e0SPeter Maydell     }
67fcf5ef2aSThomas Huth     /* Unknown register.  */
68fcf5ef2aSThomas Huth     return 0;
69fcf5ef2aSThomas Huth }
70fcf5ef2aSThomas Huth 
71fcf5ef2aSThomas Huth int arm_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
72fcf5ef2aSThomas Huth {
73fcf5ef2aSThomas Huth     ARMCPU *cpu = ARM_CPU(cs);
74fcf5ef2aSThomas Huth     CPUARMState *env = &cpu->env;
75fcf5ef2aSThomas Huth     uint32_t tmp;
76fcf5ef2aSThomas Huth 
77fcf5ef2aSThomas Huth     tmp = ldl_p(mem_buf);
78fcf5ef2aSThomas Huth 
79fcf5ef2aSThomas Huth     /* Mask out low bit of PC to workaround gdb bugs.  This will probably
80fcf5ef2aSThomas Huth        cause problems if we ever implement the Jazelle DBX extensions.  */
81fcf5ef2aSThomas Huth     if (n == 15) {
82fcf5ef2aSThomas Huth         tmp &= ~1;
83fcf5ef2aSThomas Huth     }
84fcf5ef2aSThomas Huth 
85fcf5ef2aSThomas Huth     if (n < 16) {
86fcf5ef2aSThomas Huth         /* Core integer register.  */
87fcf5ef2aSThomas Huth         env->regs[n] = tmp;
88fcf5ef2aSThomas Huth         return 4;
89fcf5ef2aSThomas Huth     }
90fcf5ef2aSThomas Huth     if (n < 24) { /* 16-23 */
91fcf5ef2aSThomas Huth         /* FPA registers (ignored).  */
92fcf5ef2aSThomas Huth         if (gdb_has_xml) {
93fcf5ef2aSThomas Huth             return 0;
94fcf5ef2aSThomas Huth         }
95fcf5ef2aSThomas Huth         return 12;
96fcf5ef2aSThomas Huth     }
97fcf5ef2aSThomas Huth     switch (n) {
98fcf5ef2aSThomas Huth     case 24:
99fcf5ef2aSThomas Huth         /* FPA status register (ignored).  */
100fcf5ef2aSThomas Huth         if (gdb_has_xml) {
101fcf5ef2aSThomas Huth             return 0;
102fcf5ef2aSThomas Huth         }
103fcf5ef2aSThomas Huth         return 4;
104fcf5ef2aSThomas Huth     case 25:
105c888f7e0SPeter Maydell         /* CPSR, or XPSR for M-profile */
106c888f7e0SPeter Maydell         if (arm_feature(env, ARM_FEATURE_M)) {
107c888f7e0SPeter Maydell             /*
108c888f7e0SPeter Maydell              * Don't allow writing to XPSR.Exception as it can cause
109c888f7e0SPeter Maydell              * a transition into or out of handler mode (it's not
110c888f7e0SPeter Maydell              * writeable via the MSR insn so this is a reasonable
111c888f7e0SPeter Maydell              * restriction). Other fields are safe to update.
112c888f7e0SPeter Maydell              */
113c888f7e0SPeter Maydell             xpsr_write(env, tmp, ~XPSR_EXCP);
114c888f7e0SPeter Maydell         } else {
115fcf5ef2aSThomas Huth             cpsr_write(env, tmp, 0xffffffff, CPSRWriteByGDBStub);
116c888f7e0SPeter Maydell         }
117fcf5ef2aSThomas Huth         return 4;
118fcf5ef2aSThomas Huth     }
119fcf5ef2aSThomas Huth     /* Unknown register.  */
120fcf5ef2aSThomas Huth     return 0;
121fcf5ef2aSThomas Huth }
122200bf5b7SAbdallah Bouassida 
123448d4d14SAlex Bennée static void arm_gen_one_xml_sysreg_tag(GString *s, DynamicGDBXMLInfo *dyn_xml,
124200bf5b7SAbdallah Bouassida                                        ARMCPRegInfo *ri, uint32_t ri_key,
12532d6e32aSAlex Bennée                                        int bitsize, int regnum)
126200bf5b7SAbdallah Bouassida {
127200bf5b7SAbdallah Bouassida     g_string_append_printf(s, "<reg name=\"%s\"", ri->name);
128200bf5b7SAbdallah Bouassida     g_string_append_printf(s, " bitsize=\"%d\"", bitsize);
12932d6e32aSAlex Bennée     g_string_append_printf(s, " regnum=\"%d\"", regnum);
130200bf5b7SAbdallah Bouassida     g_string_append_printf(s, " group=\"cp_regs\"/>");
131448d4d14SAlex Bennée     dyn_xml->data.cpregs.keys[dyn_xml->num] = ri_key;
132448d4d14SAlex Bennée     dyn_xml->num++;
133200bf5b7SAbdallah Bouassida }
134200bf5b7SAbdallah Bouassida 
135200bf5b7SAbdallah Bouassida static void arm_register_sysreg_for_xml(gpointer key, gpointer value,
136200bf5b7SAbdallah Bouassida                                         gpointer p)
137200bf5b7SAbdallah Bouassida {
138200bf5b7SAbdallah Bouassida     uint32_t ri_key = *(uint32_t *)key;
139200bf5b7SAbdallah Bouassida     ARMCPRegInfo *ri = value;
140200bf5b7SAbdallah Bouassida     RegisterSysregXmlParam *param = (RegisterSysregXmlParam *)p;
141200bf5b7SAbdallah Bouassida     GString *s = param->s;
142200bf5b7SAbdallah Bouassida     ARMCPU *cpu = ARM_CPU(param->cs);
143200bf5b7SAbdallah Bouassida     CPUARMState *env = &cpu->env;
144448d4d14SAlex Bennée     DynamicGDBXMLInfo *dyn_xml = &cpu->dyn_sysreg_xml;
145200bf5b7SAbdallah Bouassida 
146200bf5b7SAbdallah Bouassida     if (!(ri->type & (ARM_CP_NO_RAW | ARM_CP_NO_GDB))) {
147200bf5b7SAbdallah Bouassida         if (arm_feature(env, ARM_FEATURE_AARCH64)) {
148200bf5b7SAbdallah Bouassida             if (ri->state == ARM_CP_STATE_AA64) {
14932d6e32aSAlex Bennée                 arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 64,
15032d6e32aSAlex Bennée                                            param->n++);
151200bf5b7SAbdallah Bouassida             }
152200bf5b7SAbdallah Bouassida         } else {
153200bf5b7SAbdallah Bouassida             if (ri->state == ARM_CP_STATE_AA32) {
154200bf5b7SAbdallah Bouassida                 if (!arm_feature(env, ARM_FEATURE_EL3) &&
155200bf5b7SAbdallah Bouassida                     (ri->secure & ARM_CP_SECSTATE_S)) {
156200bf5b7SAbdallah Bouassida                     return;
157200bf5b7SAbdallah Bouassida                 }
158200bf5b7SAbdallah Bouassida                 if (ri->type & ARM_CP_64BIT) {
15932d6e32aSAlex Bennée                     arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 64,
16032d6e32aSAlex Bennée                                                param->n++);
161200bf5b7SAbdallah Bouassida                 } else {
16232d6e32aSAlex Bennée                     arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 32,
16332d6e32aSAlex Bennée                                                param->n++);
164200bf5b7SAbdallah Bouassida                 }
165200bf5b7SAbdallah Bouassida             }
166200bf5b7SAbdallah Bouassida         }
167200bf5b7SAbdallah Bouassida     }
168200bf5b7SAbdallah Bouassida }
169200bf5b7SAbdallah Bouassida 
17032d6e32aSAlex Bennée int arm_gen_dynamic_sysreg_xml(CPUState *cs, int base_reg)
171200bf5b7SAbdallah Bouassida {
172200bf5b7SAbdallah Bouassida     ARMCPU *cpu = ARM_CPU(cs);
173200bf5b7SAbdallah Bouassida     GString *s = g_string_new(NULL);
17432d6e32aSAlex Bennée     RegisterSysregXmlParam param = {cs, s, base_reg};
175200bf5b7SAbdallah Bouassida 
176448d4d14SAlex Bennée     cpu->dyn_sysreg_xml.num = 0;
177448d4d14SAlex Bennée     cpu->dyn_sysreg_xml.data.cpregs.keys = g_new(uint32_t, g_hash_table_size(cpu->cp_regs));
178200bf5b7SAbdallah Bouassida     g_string_printf(s, "<?xml version=\"1.0\"?>");
179200bf5b7SAbdallah Bouassida     g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">");
180200bf5b7SAbdallah Bouassida     g_string_append_printf(s, "<feature name=\"org.qemu.gdb.arm.sys.regs\">");
181200bf5b7SAbdallah Bouassida     g_hash_table_foreach(cpu->cp_regs, arm_register_sysreg_for_xml, &param);
182200bf5b7SAbdallah Bouassida     g_string_append_printf(s, "</feature>");
183448d4d14SAlex Bennée     cpu->dyn_sysreg_xml.desc = g_string_free(s, false);
184448d4d14SAlex Bennée     return cpu->dyn_sysreg_xml.num;
185200bf5b7SAbdallah Bouassida }
186200bf5b7SAbdallah Bouassida 
187d12379c5SAlex Bennée struct TypeSize {
188d12379c5SAlex Bennée     const char *gdb_type;
189d12379c5SAlex Bennée     int  size;
190d12379c5SAlex Bennée     const char sz, suffix;
191d12379c5SAlex Bennée };
192d12379c5SAlex Bennée 
193d12379c5SAlex Bennée static const struct TypeSize vec_lanes[] = {
194d12379c5SAlex Bennée     /* quads */
195d12379c5SAlex Bennée     { "uint128", 128, 'q', 'u' },
196d12379c5SAlex Bennée     { "int128", 128, 'q', 's' },
197d12379c5SAlex Bennée     /* 64 bit */
198*797920b9SAlex Bennée     { "ieee_double", 64, 'd', 'f' },
199d12379c5SAlex Bennée     { "uint64", 64, 'd', 'u' },
200d12379c5SAlex Bennée     { "int64", 64, 'd', 's' },
201d12379c5SAlex Bennée     /* 32 bit */
202*797920b9SAlex Bennée     { "ieee_single", 32, 's', 'f' },
203d12379c5SAlex Bennée     { "uint32", 32, 's', 'u' },
204d12379c5SAlex Bennée     { "int32", 32, 's', 's' },
205d12379c5SAlex Bennée     /* 16 bit */
206*797920b9SAlex Bennée     { "ieee_half", 16, 'h', 'f' },
207d12379c5SAlex Bennée     { "uint16", 16, 'h', 'u' },
208d12379c5SAlex Bennée     { "int16", 16, 'h', 's' },
209d12379c5SAlex Bennée     /* bytes */
210d12379c5SAlex Bennée     { "uint8", 8, 'b', 'u' },
211d12379c5SAlex Bennée     { "int8", 8, 'b', 's' },
212d12379c5SAlex Bennée };
213d12379c5SAlex Bennée 
214d12379c5SAlex Bennée 
215d12379c5SAlex Bennée int arm_gen_dynamic_svereg_xml(CPUState *cs, int base_reg)
216d12379c5SAlex Bennée {
217d12379c5SAlex Bennée     ARMCPU *cpu = ARM_CPU(cs);
218d12379c5SAlex Bennée     GString *s = g_string_new(NULL);
219d12379c5SAlex Bennée     DynamicGDBXMLInfo *info = &cpu->dyn_svereg_xml;
220d12379c5SAlex Bennée     g_autoptr(GString) ts = g_string_new("");
221*797920b9SAlex Bennée     int i, j, bits, reg_width = (cpu->sve_max_vq * 128);
222d12379c5SAlex Bennée     info->num = 0;
223d12379c5SAlex Bennée     g_string_printf(s, "<?xml version=\"1.0\"?>");
224d12379c5SAlex Bennée     g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">");
225*797920b9SAlex Bennée     g_string_append_printf(s, "<feature name=\"org.gnu.gdb.aarch64.sve\">");
226d12379c5SAlex Bennée 
227d12379c5SAlex Bennée     /* First define types and totals in a whole VL */
228d12379c5SAlex Bennée     for (i = 0; i < ARRAY_SIZE(vec_lanes); i++) {
229d12379c5SAlex Bennée         int count = reg_width / vec_lanes[i].size;
230*797920b9SAlex Bennée         g_string_printf(ts, "svev%c%c", vec_lanes[i].sz, vec_lanes[i].suffix);
231d12379c5SAlex Bennée         g_string_append_printf(s,
232d12379c5SAlex Bennée                                "<vector id=\"%s\" type=\"%s\" count=\"%d\"/>",
233d12379c5SAlex Bennée                                ts->str, vec_lanes[i].gdb_type, count);
234d12379c5SAlex Bennée     }
235d12379c5SAlex Bennée     /*
236d12379c5SAlex Bennée      * Now define a union for each size group containing unsigned and
237d12379c5SAlex Bennée      * signed and potentially float versions of each size from 128 to
238d12379c5SAlex Bennée      * 8 bits.
239d12379c5SAlex Bennée      */
240*797920b9SAlex Bennée     for (bits = 128, i = 0; bits >= 8; bits /= 2, i++) {
241*797920b9SAlex Bennée         const char suf[] = { 'q', 'd', 's', 'h', 'b' };
242*797920b9SAlex Bennée         g_string_append_printf(s, "<union id=\"svevn%c\">", suf[i]);
243*797920b9SAlex Bennée         for (j = 0; j < ARRAY_SIZE(vec_lanes); j++) {
244*797920b9SAlex Bennée             if (vec_lanes[j].size == bits) {
245*797920b9SAlex Bennée                 g_string_append_printf(s, "<field name=\"%c\" type=\"svev%c%c\"/>",
246*797920b9SAlex Bennée                                        vec_lanes[j].suffix,
247*797920b9SAlex Bennée                                        vec_lanes[j].sz, vec_lanes[j].suffix);
248d12379c5SAlex Bennée             }
249d12379c5SAlex Bennée         }
250d12379c5SAlex Bennée         g_string_append(s, "</union>");
251d12379c5SAlex Bennée     }
252d12379c5SAlex Bennée     /* And now the final union of unions */
253*797920b9SAlex Bennée     g_string_append(s, "<union id=\"svev\">");
254*797920b9SAlex Bennée     for (bits = 128, i = 0; bits >= 8; bits /= 2, i++) {
255*797920b9SAlex Bennée         const char suf[] = { 'q', 'd', 's', 'h', 'b' };
256*797920b9SAlex Bennée         g_string_append_printf(s, "<field name=\"%c\" type=\"svevn%c\"/>",
257*797920b9SAlex Bennée                                suf[i], suf[i]);
258d12379c5SAlex Bennée     }
259d12379c5SAlex Bennée     g_string_append(s, "</union>");
260d12379c5SAlex Bennée 
261*797920b9SAlex Bennée     /* Finally the sve prefix type */
262*797920b9SAlex Bennée     g_string_append_printf(s,
263*797920b9SAlex Bennée                            "<vector id=\"svep\" type=\"uint8\" count=\"%d\"/>",
264*797920b9SAlex Bennée                            reg_width / 8);
265*797920b9SAlex Bennée 
266d12379c5SAlex Bennée     /* Then define each register in parts for each vq */
267d12379c5SAlex Bennée     for (i = 0; i < 32; i++) {
268d12379c5SAlex Bennée         g_string_append_printf(s,
269d12379c5SAlex Bennée                                "<reg name=\"z%d\" bitsize=\"%d\""
270*797920b9SAlex Bennée                                " regnum=\"%d\" type=\"svev\"/>",
271d12379c5SAlex Bennée                                i, reg_width, base_reg++);
272d12379c5SAlex Bennée         info->num++;
273d12379c5SAlex Bennée     }
274d12379c5SAlex Bennée     /* fpscr & status registers */
275d12379c5SAlex Bennée     g_string_append_printf(s, "<reg name=\"fpsr\" bitsize=\"32\""
276d12379c5SAlex Bennée                            " regnum=\"%d\" group=\"float\""
277d12379c5SAlex Bennée                            " type=\"int\"/>", base_reg++);
278d12379c5SAlex Bennée     g_string_append_printf(s, "<reg name=\"fpcr\" bitsize=\"32\""
279d12379c5SAlex Bennée                            " regnum=\"%d\" group=\"float\""
280d12379c5SAlex Bennée                            " type=\"int\"/>", base_reg++);
281d12379c5SAlex Bennée     info->num += 2;
282*797920b9SAlex Bennée 
283d12379c5SAlex Bennée     for (i = 0; i < 16; i++) {
284d12379c5SAlex Bennée         g_string_append_printf(s,
285d12379c5SAlex Bennée                                "<reg name=\"p%d\" bitsize=\"%d\""
286*797920b9SAlex Bennée                                " regnum=\"%d\" type=\"svep\"/>",
287d12379c5SAlex Bennée                                i, cpu->sve_max_vq * 16, base_reg++);
288d12379c5SAlex Bennée         info->num++;
289d12379c5SAlex Bennée     }
290d12379c5SAlex Bennée     g_string_append_printf(s,
291d12379c5SAlex Bennée                            "<reg name=\"ffr\" bitsize=\"%d\""
292d12379c5SAlex Bennée                            " regnum=\"%d\" group=\"vector\""
293*797920b9SAlex Bennée                            " type=\"svep\"/>",
294d12379c5SAlex Bennée                            cpu->sve_max_vq * 16, base_reg++);
295d12379c5SAlex Bennée     g_string_append_printf(s,
296d12379c5SAlex Bennée                            "<reg name=\"vg\" bitsize=\"64\""
297*797920b9SAlex Bennée                            " regnum=\"%d\" type=\"int\"/>",
298d12379c5SAlex Bennée                            base_reg++);
299d12379c5SAlex Bennée     info->num += 2;
300d12379c5SAlex Bennée     g_string_append_printf(s, "</feature>");
301d12379c5SAlex Bennée     cpu->dyn_svereg_xml.desc = g_string_free(s, false);
302d12379c5SAlex Bennée 
303d12379c5SAlex Bennée     return cpu->dyn_svereg_xml.num;
304d12379c5SAlex Bennée }
305d12379c5SAlex Bennée 
306d12379c5SAlex Bennée 
307200bf5b7SAbdallah Bouassida const char *arm_gdb_get_dynamic_xml(CPUState *cs, const char *xmlname)
308200bf5b7SAbdallah Bouassida {
309200bf5b7SAbdallah Bouassida     ARMCPU *cpu = ARM_CPU(cs);
310200bf5b7SAbdallah Bouassida 
311200bf5b7SAbdallah Bouassida     if (strcmp(xmlname, "system-registers.xml") == 0) {
312448d4d14SAlex Bennée         return cpu->dyn_sysreg_xml.desc;
313d12379c5SAlex Bennée     } else if (strcmp(xmlname, "sve-registers.xml") == 0) {
314d12379c5SAlex Bennée         return cpu->dyn_svereg_xml.desc;
315200bf5b7SAbdallah Bouassida     }
316200bf5b7SAbdallah Bouassida     return NULL;
317200bf5b7SAbdallah Bouassida }
318