xref: /openbmc/qemu/target/arm/gdbstub.c (revision 200bf5b7ffea635079cc05fdfb363372b9544ce7)
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 "qemu-common.h"
22fcf5ef2aSThomas Huth #include "cpu.h"
23fcf5ef2aSThomas Huth #include "exec/gdbstub.h"
24fcf5ef2aSThomas Huth 
25*200bf5b7SAbdallah Bouassida typedef struct RegisterSysregXmlParam {
26*200bf5b7SAbdallah Bouassida     CPUState *cs;
27*200bf5b7SAbdallah Bouassida     GString *s;
28*200bf5b7SAbdallah Bouassida } RegisterSysregXmlParam;
29*200bf5b7SAbdallah 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 
36fcf5ef2aSThomas Huth int arm_cpu_gdb_read_register(CPUState *cs, uint8_t *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         }
50fcf5ef2aSThomas Huth         memset(mem_buf, 0, 12);
51fcf5ef2aSThomas Huth         return 12;
52fcf5ef2aSThomas Huth     }
53fcf5ef2aSThomas Huth     switch (n) {
54fcf5ef2aSThomas Huth     case 24:
55fcf5ef2aSThomas Huth         /* FPA status register.  */
56fcf5ef2aSThomas Huth         if (gdb_has_xml) {
57fcf5ef2aSThomas Huth             return 0;
58fcf5ef2aSThomas Huth         }
59fcf5ef2aSThomas Huth         return gdb_get_reg32(mem_buf, 0);
60fcf5ef2aSThomas Huth     case 25:
61fcf5ef2aSThomas Huth         /* CPSR */
62fcf5ef2aSThomas Huth         return gdb_get_reg32(mem_buf, cpsr_read(env));
63fcf5ef2aSThomas Huth     }
64fcf5ef2aSThomas Huth     /* Unknown register.  */
65fcf5ef2aSThomas Huth     return 0;
66fcf5ef2aSThomas Huth }
67fcf5ef2aSThomas Huth 
68fcf5ef2aSThomas Huth int arm_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
69fcf5ef2aSThomas Huth {
70fcf5ef2aSThomas Huth     ARMCPU *cpu = ARM_CPU(cs);
71fcf5ef2aSThomas Huth     CPUARMState *env = &cpu->env;
72fcf5ef2aSThomas Huth     uint32_t tmp;
73fcf5ef2aSThomas Huth 
74fcf5ef2aSThomas Huth     tmp = ldl_p(mem_buf);
75fcf5ef2aSThomas Huth 
76fcf5ef2aSThomas Huth     /* Mask out low bit of PC to workaround gdb bugs.  This will probably
77fcf5ef2aSThomas Huth        cause problems if we ever implement the Jazelle DBX extensions.  */
78fcf5ef2aSThomas Huth     if (n == 15) {
79fcf5ef2aSThomas Huth         tmp &= ~1;
80fcf5ef2aSThomas Huth     }
81fcf5ef2aSThomas Huth 
82fcf5ef2aSThomas Huth     if (n < 16) {
83fcf5ef2aSThomas Huth         /* Core integer register.  */
84fcf5ef2aSThomas Huth         env->regs[n] = tmp;
85fcf5ef2aSThomas Huth         return 4;
86fcf5ef2aSThomas Huth     }
87fcf5ef2aSThomas Huth     if (n < 24) { /* 16-23 */
88fcf5ef2aSThomas Huth         /* FPA registers (ignored).  */
89fcf5ef2aSThomas Huth         if (gdb_has_xml) {
90fcf5ef2aSThomas Huth             return 0;
91fcf5ef2aSThomas Huth         }
92fcf5ef2aSThomas Huth         return 12;
93fcf5ef2aSThomas Huth     }
94fcf5ef2aSThomas Huth     switch (n) {
95fcf5ef2aSThomas Huth     case 24:
96fcf5ef2aSThomas Huth         /* FPA status register (ignored).  */
97fcf5ef2aSThomas Huth         if (gdb_has_xml) {
98fcf5ef2aSThomas Huth             return 0;
99fcf5ef2aSThomas Huth         }
100fcf5ef2aSThomas Huth         return 4;
101fcf5ef2aSThomas Huth     case 25:
102fcf5ef2aSThomas Huth         /* CPSR */
103fcf5ef2aSThomas Huth         cpsr_write(env, tmp, 0xffffffff, CPSRWriteByGDBStub);
104fcf5ef2aSThomas Huth         return 4;
105fcf5ef2aSThomas Huth     }
106fcf5ef2aSThomas Huth     /* Unknown register.  */
107fcf5ef2aSThomas Huth     return 0;
108fcf5ef2aSThomas Huth }
109*200bf5b7SAbdallah Bouassida 
110*200bf5b7SAbdallah Bouassida static void arm_gen_one_xml_reg_tag(GString *s, DynamicGDBXMLInfo *dyn_xml,
111*200bf5b7SAbdallah Bouassida                                     ARMCPRegInfo *ri, uint32_t ri_key,
112*200bf5b7SAbdallah Bouassida                                     int bitsize)
113*200bf5b7SAbdallah Bouassida {
114*200bf5b7SAbdallah Bouassida     g_string_append_printf(s, "<reg name=\"%s\"", ri->name);
115*200bf5b7SAbdallah Bouassida     g_string_append_printf(s, " bitsize=\"%d\"", bitsize);
116*200bf5b7SAbdallah Bouassida     g_string_append_printf(s, " group=\"cp_regs\"/>");
117*200bf5b7SAbdallah Bouassida     dyn_xml->num_cpregs++;
118*200bf5b7SAbdallah Bouassida     dyn_xml->cpregs_keys[dyn_xml->num_cpregs - 1] = ri_key;
119*200bf5b7SAbdallah Bouassida }
120*200bf5b7SAbdallah Bouassida 
121*200bf5b7SAbdallah Bouassida static void arm_register_sysreg_for_xml(gpointer key, gpointer value,
122*200bf5b7SAbdallah Bouassida                                         gpointer p)
123*200bf5b7SAbdallah Bouassida {
124*200bf5b7SAbdallah Bouassida     uint32_t ri_key = *(uint32_t *)key;
125*200bf5b7SAbdallah Bouassida     ARMCPRegInfo *ri = value;
126*200bf5b7SAbdallah Bouassida     RegisterSysregXmlParam *param = (RegisterSysregXmlParam *)p;
127*200bf5b7SAbdallah Bouassida     GString *s = param->s;
128*200bf5b7SAbdallah Bouassida     ARMCPU *cpu = ARM_CPU(param->cs);
129*200bf5b7SAbdallah Bouassida     CPUARMState *env = &cpu->env;
130*200bf5b7SAbdallah Bouassida     DynamicGDBXMLInfo *dyn_xml = &cpu->dyn_xml;
131*200bf5b7SAbdallah Bouassida 
132*200bf5b7SAbdallah Bouassida     if (!(ri->type & (ARM_CP_NO_RAW | ARM_CP_NO_GDB))) {
133*200bf5b7SAbdallah Bouassida         if (arm_feature(env, ARM_FEATURE_AARCH64)) {
134*200bf5b7SAbdallah Bouassida             if (ri->state == ARM_CP_STATE_AA64) {
135*200bf5b7SAbdallah Bouassida                 arm_gen_one_xml_reg_tag(s , dyn_xml, ri, ri_key, 64);
136*200bf5b7SAbdallah Bouassida             }
137*200bf5b7SAbdallah Bouassida         } else {
138*200bf5b7SAbdallah Bouassida             if (ri->state == ARM_CP_STATE_AA32) {
139*200bf5b7SAbdallah Bouassida                 if (!arm_feature(env, ARM_FEATURE_EL3) &&
140*200bf5b7SAbdallah Bouassida                     (ri->secure & ARM_CP_SECSTATE_S)) {
141*200bf5b7SAbdallah Bouassida                     return;
142*200bf5b7SAbdallah Bouassida                 }
143*200bf5b7SAbdallah Bouassida                 if (ri->type & ARM_CP_64BIT) {
144*200bf5b7SAbdallah Bouassida                     arm_gen_one_xml_reg_tag(s , dyn_xml, ri, ri_key, 64);
145*200bf5b7SAbdallah Bouassida                 } else {
146*200bf5b7SAbdallah Bouassida                     arm_gen_one_xml_reg_tag(s , dyn_xml, ri, ri_key, 32);
147*200bf5b7SAbdallah Bouassida                 }
148*200bf5b7SAbdallah Bouassida             }
149*200bf5b7SAbdallah Bouassida         }
150*200bf5b7SAbdallah Bouassida     }
151*200bf5b7SAbdallah Bouassida }
152*200bf5b7SAbdallah Bouassida 
153*200bf5b7SAbdallah Bouassida int arm_gen_dynamic_xml(CPUState *cs)
154*200bf5b7SAbdallah Bouassida {
155*200bf5b7SAbdallah Bouassida     ARMCPU *cpu = ARM_CPU(cs);
156*200bf5b7SAbdallah Bouassida     GString *s = g_string_new(NULL);
157*200bf5b7SAbdallah Bouassida     RegisterSysregXmlParam param = {cs, s};
158*200bf5b7SAbdallah Bouassida 
159*200bf5b7SAbdallah Bouassida     cpu->dyn_xml.num_cpregs = 0;
160*200bf5b7SAbdallah Bouassida     cpu->dyn_xml.cpregs_keys = g_malloc(sizeof(uint32_t *) *
161*200bf5b7SAbdallah Bouassida                                         g_hash_table_size(cpu->cp_regs));
162*200bf5b7SAbdallah Bouassida     g_string_printf(s, "<?xml version=\"1.0\"?>");
163*200bf5b7SAbdallah Bouassida     g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">");
164*200bf5b7SAbdallah Bouassida     g_string_append_printf(s, "<feature name=\"org.qemu.gdb.arm.sys.regs\">");
165*200bf5b7SAbdallah Bouassida     g_hash_table_foreach(cpu->cp_regs, arm_register_sysreg_for_xml, &param);
166*200bf5b7SAbdallah Bouassida     g_string_append_printf(s, "</feature>");
167*200bf5b7SAbdallah Bouassida     cpu->dyn_xml.desc = g_string_free(s, false);
168*200bf5b7SAbdallah Bouassida     return cpu->dyn_xml.num_cpregs;
169*200bf5b7SAbdallah Bouassida }
170*200bf5b7SAbdallah Bouassida 
171*200bf5b7SAbdallah Bouassida const char *arm_gdb_get_dynamic_xml(CPUState *cs, const char *xmlname)
172*200bf5b7SAbdallah Bouassida {
173*200bf5b7SAbdallah Bouassida     ARMCPU *cpu = ARM_CPU(cs);
174*200bf5b7SAbdallah Bouassida 
175*200bf5b7SAbdallah Bouassida     if (strcmp(xmlname, "system-registers.xml") == 0) {
176*200bf5b7SAbdallah Bouassida         return cpu->dyn_xml.desc;
177*200bf5b7SAbdallah Bouassida     }
178*200bf5b7SAbdallah Bouassida     return NULL;
179*200bf5b7SAbdallah Bouassida }
180