xref: /openbmc/qemu/target/arm/gdbstub.c (revision 448d4d146b788898d56131d21001542f39681c9b)
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
10fcf5ef2aSThomas Huth  * version 2 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;
27200bf5b7SAbdallah Bouassida } RegisterSysregXmlParam;
28200bf5b7SAbdallah Bouassida 
29fcf5ef2aSThomas Huth /* Old gdb always expect FPA registers.  Newer (xml-aware) gdb only expect
30fcf5ef2aSThomas Huth    whatever the target description contains.  Due to a historical mishap
31fcf5ef2aSThomas Huth    the FPA registers appear in between core integer regs and the CPSR.
32fcf5ef2aSThomas Huth    We hack round this by giving the FPA regs zero size when talking to a
33fcf5ef2aSThomas Huth    newer gdb.  */
34fcf5ef2aSThomas Huth 
35a010bdbeSAlex Bennée int arm_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
36fcf5ef2aSThomas Huth {
37fcf5ef2aSThomas Huth     ARMCPU *cpu = ARM_CPU(cs);
38fcf5ef2aSThomas Huth     CPUARMState *env = &cpu->env;
39fcf5ef2aSThomas Huth 
40fcf5ef2aSThomas Huth     if (n < 16) {
41fcf5ef2aSThomas Huth         /* Core integer register.  */
42fcf5ef2aSThomas Huth         return gdb_get_reg32(mem_buf, env->regs[n]);
43fcf5ef2aSThomas Huth     }
44fcf5ef2aSThomas Huth     if (n < 24) {
45fcf5ef2aSThomas Huth         /* FPA registers.  */
46fcf5ef2aSThomas Huth         if (gdb_has_xml) {
47fcf5ef2aSThomas Huth             return 0;
48fcf5ef2aSThomas Huth         }
49fcf5ef2aSThomas Huth         memset(mem_buf, 0, 12);
50fcf5ef2aSThomas Huth         return 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:
60fcf5ef2aSThomas Huth         /* CPSR */
61fcf5ef2aSThomas Huth         return gdb_get_reg32(mem_buf, cpsr_read(env));
62fcf5ef2aSThomas Huth     }
63fcf5ef2aSThomas Huth     /* Unknown register.  */
64fcf5ef2aSThomas Huth     return 0;
65fcf5ef2aSThomas Huth }
66fcf5ef2aSThomas Huth 
67fcf5ef2aSThomas Huth int arm_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
68fcf5ef2aSThomas Huth {
69fcf5ef2aSThomas Huth     ARMCPU *cpu = ARM_CPU(cs);
70fcf5ef2aSThomas Huth     CPUARMState *env = &cpu->env;
71fcf5ef2aSThomas Huth     uint32_t tmp;
72fcf5ef2aSThomas Huth 
73fcf5ef2aSThomas Huth     tmp = ldl_p(mem_buf);
74fcf5ef2aSThomas Huth 
75fcf5ef2aSThomas Huth     /* Mask out low bit of PC to workaround gdb bugs.  This will probably
76fcf5ef2aSThomas Huth        cause problems if we ever implement the Jazelle DBX extensions.  */
77fcf5ef2aSThomas Huth     if (n == 15) {
78fcf5ef2aSThomas Huth         tmp &= ~1;
79fcf5ef2aSThomas Huth     }
80fcf5ef2aSThomas Huth 
81fcf5ef2aSThomas Huth     if (n < 16) {
82fcf5ef2aSThomas Huth         /* Core integer register.  */
83fcf5ef2aSThomas Huth         env->regs[n] = tmp;
84fcf5ef2aSThomas Huth         return 4;
85fcf5ef2aSThomas Huth     }
86fcf5ef2aSThomas Huth     if (n < 24) { /* 16-23 */
87fcf5ef2aSThomas Huth         /* FPA registers (ignored).  */
88fcf5ef2aSThomas Huth         if (gdb_has_xml) {
89fcf5ef2aSThomas Huth             return 0;
90fcf5ef2aSThomas Huth         }
91fcf5ef2aSThomas Huth         return 12;
92fcf5ef2aSThomas Huth     }
93fcf5ef2aSThomas Huth     switch (n) {
94fcf5ef2aSThomas Huth     case 24:
95fcf5ef2aSThomas Huth         /* FPA status register (ignored).  */
96fcf5ef2aSThomas Huth         if (gdb_has_xml) {
97fcf5ef2aSThomas Huth             return 0;
98fcf5ef2aSThomas Huth         }
99fcf5ef2aSThomas Huth         return 4;
100fcf5ef2aSThomas Huth     case 25:
101fcf5ef2aSThomas Huth         /* CPSR */
102fcf5ef2aSThomas Huth         cpsr_write(env, tmp, 0xffffffff, CPSRWriteByGDBStub);
103fcf5ef2aSThomas Huth         return 4;
104fcf5ef2aSThomas Huth     }
105fcf5ef2aSThomas Huth     /* Unknown register.  */
106fcf5ef2aSThomas Huth     return 0;
107fcf5ef2aSThomas Huth }
108200bf5b7SAbdallah Bouassida 
109*448d4d14SAlex Bennée static void arm_gen_one_xml_sysreg_tag(GString *s, DynamicGDBXMLInfo *dyn_xml,
110200bf5b7SAbdallah Bouassida                                        ARMCPRegInfo *ri, uint32_t ri_key,
111200bf5b7SAbdallah Bouassida                                        int bitsize)
112200bf5b7SAbdallah Bouassida {
113200bf5b7SAbdallah Bouassida     g_string_append_printf(s, "<reg name=\"%s\"", ri->name);
114200bf5b7SAbdallah Bouassida     g_string_append_printf(s, " bitsize=\"%d\"", bitsize);
115200bf5b7SAbdallah Bouassida     g_string_append_printf(s, " group=\"cp_regs\"/>");
116*448d4d14SAlex Bennée     dyn_xml->data.cpregs.keys[dyn_xml->num] = ri_key;
117*448d4d14SAlex Bennée     dyn_xml->num++;
118200bf5b7SAbdallah Bouassida }
119200bf5b7SAbdallah Bouassida 
120200bf5b7SAbdallah Bouassida static void arm_register_sysreg_for_xml(gpointer key, gpointer value,
121200bf5b7SAbdallah Bouassida                                         gpointer p)
122200bf5b7SAbdallah Bouassida {
123200bf5b7SAbdallah Bouassida     uint32_t ri_key = *(uint32_t *)key;
124200bf5b7SAbdallah Bouassida     ARMCPRegInfo *ri = value;
125200bf5b7SAbdallah Bouassida     RegisterSysregXmlParam *param = (RegisterSysregXmlParam *)p;
126200bf5b7SAbdallah Bouassida     GString *s = param->s;
127200bf5b7SAbdallah Bouassida     ARMCPU *cpu = ARM_CPU(param->cs);
128200bf5b7SAbdallah Bouassida     CPUARMState *env = &cpu->env;
129*448d4d14SAlex Bennée     DynamicGDBXMLInfo *dyn_xml = &cpu->dyn_sysreg_xml;
130200bf5b7SAbdallah Bouassida 
131200bf5b7SAbdallah Bouassida     if (!(ri->type & (ARM_CP_NO_RAW | ARM_CP_NO_GDB))) {
132200bf5b7SAbdallah Bouassida         if (arm_feature(env, ARM_FEATURE_AARCH64)) {
133200bf5b7SAbdallah Bouassida             if (ri->state == ARM_CP_STATE_AA64) {
134*448d4d14SAlex Bennée                 arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 64);
135200bf5b7SAbdallah Bouassida             }
136200bf5b7SAbdallah Bouassida         } else {
137200bf5b7SAbdallah Bouassida             if (ri->state == ARM_CP_STATE_AA32) {
138200bf5b7SAbdallah Bouassida                 if (!arm_feature(env, ARM_FEATURE_EL3) &&
139200bf5b7SAbdallah Bouassida                     (ri->secure & ARM_CP_SECSTATE_S)) {
140200bf5b7SAbdallah Bouassida                     return;
141200bf5b7SAbdallah Bouassida                 }
142200bf5b7SAbdallah Bouassida                 if (ri->type & ARM_CP_64BIT) {
143*448d4d14SAlex Bennée                     arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 64);
144200bf5b7SAbdallah Bouassida                 } else {
145*448d4d14SAlex Bennée                     arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 32);
146200bf5b7SAbdallah Bouassida                 }
147200bf5b7SAbdallah Bouassida             }
148200bf5b7SAbdallah Bouassida         }
149200bf5b7SAbdallah Bouassida     }
150200bf5b7SAbdallah Bouassida }
151200bf5b7SAbdallah Bouassida 
152*448d4d14SAlex Bennée int arm_gen_dynamic_sysreg_xml(CPUState *cs)
153200bf5b7SAbdallah Bouassida {
154200bf5b7SAbdallah Bouassida     ARMCPU *cpu = ARM_CPU(cs);
155200bf5b7SAbdallah Bouassida     GString *s = g_string_new(NULL);
156200bf5b7SAbdallah Bouassida     RegisterSysregXmlParam param = {cs, s};
157200bf5b7SAbdallah Bouassida 
158*448d4d14SAlex Bennée     cpu->dyn_sysreg_xml.num = 0;
159*448d4d14SAlex Bennée     cpu->dyn_sysreg_xml.data.cpregs.keys = g_new(uint32_t, g_hash_table_size(cpu->cp_regs));
160200bf5b7SAbdallah Bouassida     g_string_printf(s, "<?xml version=\"1.0\"?>");
161200bf5b7SAbdallah Bouassida     g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">");
162200bf5b7SAbdallah Bouassida     g_string_append_printf(s, "<feature name=\"org.qemu.gdb.arm.sys.regs\">");
163200bf5b7SAbdallah Bouassida     g_hash_table_foreach(cpu->cp_regs, arm_register_sysreg_for_xml, &param);
164200bf5b7SAbdallah Bouassida     g_string_append_printf(s, "</feature>");
165*448d4d14SAlex Bennée     cpu->dyn_sysreg_xml.desc = g_string_free(s, false);
166*448d4d14SAlex Bennée     return cpu->dyn_sysreg_xml.num;
167200bf5b7SAbdallah Bouassida }
168200bf5b7SAbdallah Bouassida 
169200bf5b7SAbdallah Bouassida const char *arm_gdb_get_dynamic_xml(CPUState *cs, const char *xmlname)
170200bf5b7SAbdallah Bouassida {
171200bf5b7SAbdallah Bouassida     ARMCPU *cpu = ARM_CPU(cs);
172200bf5b7SAbdallah Bouassida 
173200bf5b7SAbdallah Bouassida     if (strcmp(xmlname, "system-registers.xml") == 0) {
174*448d4d14SAlex Bennée         return cpu->dyn_sysreg_xml.desc;
175200bf5b7SAbdallah Bouassida     }
176200bf5b7SAbdallah Bouassida     return NULL;
177200bf5b7SAbdallah Bouassida }
178