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. */ 87*888f470fSPeter Maydell if (n == 13 && arm_feature(env, ARM_FEATURE_M)) { 88*888f470fSPeter Maydell /* M profile SP low bits are always 0 */ 89*888f470fSPeter Maydell tmp &= ~3; 90*888f470fSPeter Maydell } 91fcf5ef2aSThomas Huth env->regs[n] = tmp; 92fcf5ef2aSThomas Huth return 4; 93fcf5ef2aSThomas Huth } 94fcf5ef2aSThomas Huth if (n < 24) { /* 16-23 */ 95fcf5ef2aSThomas Huth /* FPA registers (ignored). */ 96fcf5ef2aSThomas Huth if (gdb_has_xml) { 97fcf5ef2aSThomas Huth return 0; 98fcf5ef2aSThomas Huth } 99fcf5ef2aSThomas Huth return 12; 100fcf5ef2aSThomas Huth } 101fcf5ef2aSThomas Huth switch (n) { 102fcf5ef2aSThomas Huth case 24: 103fcf5ef2aSThomas Huth /* FPA status register (ignored). */ 104fcf5ef2aSThomas Huth if (gdb_has_xml) { 105fcf5ef2aSThomas Huth return 0; 106fcf5ef2aSThomas Huth } 107fcf5ef2aSThomas Huth return 4; 108fcf5ef2aSThomas Huth case 25: 109c888f7e0SPeter Maydell /* CPSR, or XPSR for M-profile */ 110c888f7e0SPeter Maydell if (arm_feature(env, ARM_FEATURE_M)) { 111c888f7e0SPeter Maydell /* 112c888f7e0SPeter Maydell * Don't allow writing to XPSR.Exception as it can cause 113c888f7e0SPeter Maydell * a transition into or out of handler mode (it's not 114c888f7e0SPeter Maydell * writeable via the MSR insn so this is a reasonable 115c888f7e0SPeter Maydell * restriction). Other fields are safe to update. 116c888f7e0SPeter Maydell */ 117c888f7e0SPeter Maydell xpsr_write(env, tmp, ~XPSR_EXCP); 118c888f7e0SPeter Maydell } else { 119fcf5ef2aSThomas Huth cpsr_write(env, tmp, 0xffffffff, CPSRWriteByGDBStub); 120c888f7e0SPeter Maydell } 121fcf5ef2aSThomas Huth return 4; 122fcf5ef2aSThomas Huth } 123fcf5ef2aSThomas Huth /* Unknown register. */ 124fcf5ef2aSThomas Huth return 0; 125fcf5ef2aSThomas Huth } 126200bf5b7SAbdallah Bouassida 127448d4d14SAlex Bennée static void arm_gen_one_xml_sysreg_tag(GString *s, DynamicGDBXMLInfo *dyn_xml, 128200bf5b7SAbdallah Bouassida ARMCPRegInfo *ri, uint32_t ri_key, 12932d6e32aSAlex Bennée int bitsize, int regnum) 130200bf5b7SAbdallah Bouassida { 131200bf5b7SAbdallah Bouassida g_string_append_printf(s, "<reg name=\"%s\"", ri->name); 132200bf5b7SAbdallah Bouassida g_string_append_printf(s, " bitsize=\"%d\"", bitsize); 13332d6e32aSAlex Bennée g_string_append_printf(s, " regnum=\"%d\"", regnum); 134200bf5b7SAbdallah Bouassida g_string_append_printf(s, " group=\"cp_regs\"/>"); 135448d4d14SAlex Bennée dyn_xml->data.cpregs.keys[dyn_xml->num] = ri_key; 136448d4d14SAlex Bennée dyn_xml->num++; 137200bf5b7SAbdallah Bouassida } 138200bf5b7SAbdallah Bouassida 139200bf5b7SAbdallah Bouassida static void arm_register_sysreg_for_xml(gpointer key, gpointer value, 140200bf5b7SAbdallah Bouassida gpointer p) 141200bf5b7SAbdallah Bouassida { 142200bf5b7SAbdallah Bouassida uint32_t ri_key = *(uint32_t *)key; 143200bf5b7SAbdallah Bouassida ARMCPRegInfo *ri = value; 144200bf5b7SAbdallah Bouassida RegisterSysregXmlParam *param = (RegisterSysregXmlParam *)p; 145200bf5b7SAbdallah Bouassida GString *s = param->s; 146200bf5b7SAbdallah Bouassida ARMCPU *cpu = ARM_CPU(param->cs); 147200bf5b7SAbdallah Bouassida CPUARMState *env = &cpu->env; 148448d4d14SAlex Bennée DynamicGDBXMLInfo *dyn_xml = &cpu->dyn_sysreg_xml; 149200bf5b7SAbdallah Bouassida 150200bf5b7SAbdallah Bouassida if (!(ri->type & (ARM_CP_NO_RAW | ARM_CP_NO_GDB))) { 151200bf5b7SAbdallah Bouassida if (arm_feature(env, ARM_FEATURE_AARCH64)) { 152200bf5b7SAbdallah Bouassida if (ri->state == ARM_CP_STATE_AA64) { 15332d6e32aSAlex Bennée arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 64, 15432d6e32aSAlex Bennée param->n++); 155200bf5b7SAbdallah Bouassida } 156200bf5b7SAbdallah Bouassida } else { 157200bf5b7SAbdallah Bouassida if (ri->state == ARM_CP_STATE_AA32) { 158200bf5b7SAbdallah Bouassida if (!arm_feature(env, ARM_FEATURE_EL3) && 159200bf5b7SAbdallah Bouassida (ri->secure & ARM_CP_SECSTATE_S)) { 160200bf5b7SAbdallah Bouassida return; 161200bf5b7SAbdallah Bouassida } 162200bf5b7SAbdallah Bouassida if (ri->type & ARM_CP_64BIT) { 16332d6e32aSAlex Bennée arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 64, 16432d6e32aSAlex Bennée param->n++); 165200bf5b7SAbdallah Bouassida } else { 16632d6e32aSAlex Bennée arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 32, 16732d6e32aSAlex Bennée param->n++); 168200bf5b7SAbdallah Bouassida } 169200bf5b7SAbdallah Bouassida } 170200bf5b7SAbdallah Bouassida } 171200bf5b7SAbdallah Bouassida } 172200bf5b7SAbdallah Bouassida } 173200bf5b7SAbdallah Bouassida 17432d6e32aSAlex Bennée int arm_gen_dynamic_sysreg_xml(CPUState *cs, int base_reg) 175200bf5b7SAbdallah Bouassida { 176200bf5b7SAbdallah Bouassida ARMCPU *cpu = ARM_CPU(cs); 177200bf5b7SAbdallah Bouassida GString *s = g_string_new(NULL); 17832d6e32aSAlex Bennée RegisterSysregXmlParam param = {cs, s, base_reg}; 179200bf5b7SAbdallah Bouassida 180448d4d14SAlex Bennée cpu->dyn_sysreg_xml.num = 0; 181448d4d14SAlex Bennée cpu->dyn_sysreg_xml.data.cpregs.keys = g_new(uint32_t, g_hash_table_size(cpu->cp_regs)); 182200bf5b7SAbdallah Bouassida g_string_printf(s, "<?xml version=\"1.0\"?>"); 183200bf5b7SAbdallah Bouassida g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">"); 184200bf5b7SAbdallah Bouassida g_string_append_printf(s, "<feature name=\"org.qemu.gdb.arm.sys.regs\">"); 185200bf5b7SAbdallah Bouassida g_hash_table_foreach(cpu->cp_regs, arm_register_sysreg_for_xml, ¶m); 186200bf5b7SAbdallah Bouassida g_string_append_printf(s, "</feature>"); 187448d4d14SAlex Bennée cpu->dyn_sysreg_xml.desc = g_string_free(s, false); 188448d4d14SAlex Bennée return cpu->dyn_sysreg_xml.num; 189200bf5b7SAbdallah Bouassida } 190200bf5b7SAbdallah Bouassida 191d12379c5SAlex Bennée struct TypeSize { 192d12379c5SAlex Bennée const char *gdb_type; 193d12379c5SAlex Bennée int size; 194d12379c5SAlex Bennée const char sz, suffix; 195d12379c5SAlex Bennée }; 196d12379c5SAlex Bennée 197d12379c5SAlex Bennée static const struct TypeSize vec_lanes[] = { 198d12379c5SAlex Bennée /* quads */ 199d12379c5SAlex Bennée { "uint128", 128, 'q', 'u' }, 200d12379c5SAlex Bennée { "int128", 128, 'q', 's' }, 201d12379c5SAlex Bennée /* 64 bit */ 202797920b9SAlex Bennée { "ieee_double", 64, 'd', 'f' }, 203d12379c5SAlex Bennée { "uint64", 64, 'd', 'u' }, 204d12379c5SAlex Bennée { "int64", 64, 'd', 's' }, 205d12379c5SAlex Bennée /* 32 bit */ 206797920b9SAlex Bennée { "ieee_single", 32, 's', 'f' }, 207d12379c5SAlex Bennée { "uint32", 32, 's', 'u' }, 208d12379c5SAlex Bennée { "int32", 32, 's', 's' }, 209d12379c5SAlex Bennée /* 16 bit */ 210797920b9SAlex Bennée { "ieee_half", 16, 'h', 'f' }, 211d12379c5SAlex Bennée { "uint16", 16, 'h', 'u' }, 212d12379c5SAlex Bennée { "int16", 16, 'h', 's' }, 213d12379c5SAlex Bennée /* bytes */ 214d12379c5SAlex Bennée { "uint8", 8, 'b', 'u' }, 215d12379c5SAlex Bennée { "int8", 8, 'b', 's' }, 216d12379c5SAlex Bennée }; 217d12379c5SAlex Bennée 218d12379c5SAlex Bennée 219d12379c5SAlex Bennée int arm_gen_dynamic_svereg_xml(CPUState *cs, int base_reg) 220d12379c5SAlex Bennée { 221d12379c5SAlex Bennée ARMCPU *cpu = ARM_CPU(cs); 222d12379c5SAlex Bennée GString *s = g_string_new(NULL); 223d12379c5SAlex Bennée DynamicGDBXMLInfo *info = &cpu->dyn_svereg_xml; 224d12379c5SAlex Bennée g_autoptr(GString) ts = g_string_new(""); 225797920b9SAlex Bennée int i, j, bits, reg_width = (cpu->sve_max_vq * 128); 226d12379c5SAlex Bennée info->num = 0; 227d12379c5SAlex Bennée g_string_printf(s, "<?xml version=\"1.0\"?>"); 228d12379c5SAlex Bennée g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">"); 229797920b9SAlex Bennée g_string_append_printf(s, "<feature name=\"org.gnu.gdb.aarch64.sve\">"); 230d12379c5SAlex Bennée 231d12379c5SAlex Bennée /* First define types and totals in a whole VL */ 232d12379c5SAlex Bennée for (i = 0; i < ARRAY_SIZE(vec_lanes); i++) { 233d12379c5SAlex Bennée int count = reg_width / vec_lanes[i].size; 234797920b9SAlex Bennée g_string_printf(ts, "svev%c%c", vec_lanes[i].sz, vec_lanes[i].suffix); 235d12379c5SAlex Bennée g_string_append_printf(s, 236d12379c5SAlex Bennée "<vector id=\"%s\" type=\"%s\" count=\"%d\"/>", 237d12379c5SAlex Bennée ts->str, vec_lanes[i].gdb_type, count); 238d12379c5SAlex Bennée } 239d12379c5SAlex Bennée /* 240d12379c5SAlex Bennée * Now define a union for each size group containing unsigned and 241d12379c5SAlex Bennée * signed and potentially float versions of each size from 128 to 242d12379c5SAlex Bennée * 8 bits. 243d12379c5SAlex Bennée */ 244797920b9SAlex Bennée for (bits = 128, i = 0; bits >= 8; bits /= 2, i++) { 245797920b9SAlex Bennée const char suf[] = { 'q', 'd', 's', 'h', 'b' }; 246797920b9SAlex Bennée g_string_append_printf(s, "<union id=\"svevn%c\">", suf[i]); 247797920b9SAlex Bennée for (j = 0; j < ARRAY_SIZE(vec_lanes); j++) { 248797920b9SAlex Bennée if (vec_lanes[j].size == bits) { 249797920b9SAlex Bennée g_string_append_printf(s, "<field name=\"%c\" type=\"svev%c%c\"/>", 250797920b9SAlex Bennée vec_lanes[j].suffix, 251797920b9SAlex Bennée vec_lanes[j].sz, vec_lanes[j].suffix); 252d12379c5SAlex Bennée } 253d12379c5SAlex Bennée } 254d12379c5SAlex Bennée g_string_append(s, "</union>"); 255d12379c5SAlex Bennée } 256d12379c5SAlex Bennée /* And now the final union of unions */ 257797920b9SAlex Bennée g_string_append(s, "<union id=\"svev\">"); 258797920b9SAlex Bennée for (bits = 128, i = 0; bits >= 8; bits /= 2, i++) { 259797920b9SAlex Bennée const char suf[] = { 'q', 'd', 's', 'h', 'b' }; 260797920b9SAlex Bennée g_string_append_printf(s, "<field name=\"%c\" type=\"svevn%c\"/>", 261797920b9SAlex Bennée suf[i], suf[i]); 262d12379c5SAlex Bennée } 263d12379c5SAlex Bennée g_string_append(s, "</union>"); 264d12379c5SAlex Bennée 265797920b9SAlex Bennée /* Finally the sve prefix type */ 266797920b9SAlex Bennée g_string_append_printf(s, 267797920b9SAlex Bennée "<vector id=\"svep\" type=\"uint8\" count=\"%d\"/>", 268797920b9SAlex Bennée reg_width / 8); 269797920b9SAlex Bennée 270d12379c5SAlex Bennée /* Then define each register in parts for each vq */ 271d12379c5SAlex Bennée for (i = 0; i < 32; i++) { 272d12379c5SAlex Bennée g_string_append_printf(s, 273d12379c5SAlex Bennée "<reg name=\"z%d\" bitsize=\"%d\"" 274797920b9SAlex Bennée " regnum=\"%d\" type=\"svev\"/>", 275d12379c5SAlex Bennée i, reg_width, base_reg++); 276d12379c5SAlex Bennée info->num++; 277d12379c5SAlex Bennée } 278d12379c5SAlex Bennée /* fpscr & status registers */ 279d12379c5SAlex Bennée g_string_append_printf(s, "<reg name=\"fpsr\" bitsize=\"32\"" 280d12379c5SAlex Bennée " regnum=\"%d\" group=\"float\"" 281d12379c5SAlex Bennée " type=\"int\"/>", base_reg++); 282d12379c5SAlex Bennée g_string_append_printf(s, "<reg name=\"fpcr\" bitsize=\"32\"" 283d12379c5SAlex Bennée " regnum=\"%d\" group=\"float\"" 284d12379c5SAlex Bennée " type=\"int\"/>", base_reg++); 285d12379c5SAlex Bennée info->num += 2; 286797920b9SAlex Bennée 287d12379c5SAlex Bennée for (i = 0; i < 16; i++) { 288d12379c5SAlex Bennée g_string_append_printf(s, 289d12379c5SAlex Bennée "<reg name=\"p%d\" bitsize=\"%d\"" 290797920b9SAlex Bennée " regnum=\"%d\" type=\"svep\"/>", 291d12379c5SAlex Bennée i, cpu->sve_max_vq * 16, base_reg++); 292d12379c5SAlex Bennée info->num++; 293d12379c5SAlex Bennée } 294d12379c5SAlex Bennée g_string_append_printf(s, 295d12379c5SAlex Bennée "<reg name=\"ffr\" bitsize=\"%d\"" 296d12379c5SAlex Bennée " regnum=\"%d\" group=\"vector\"" 297797920b9SAlex Bennée " type=\"svep\"/>", 298d12379c5SAlex Bennée cpu->sve_max_vq * 16, base_reg++); 299d12379c5SAlex Bennée g_string_append_printf(s, 300d12379c5SAlex Bennée "<reg name=\"vg\" bitsize=\"64\"" 301797920b9SAlex Bennée " regnum=\"%d\" type=\"int\"/>", 302d12379c5SAlex Bennée base_reg++); 303d12379c5SAlex Bennée info->num += 2; 304d12379c5SAlex Bennée g_string_append_printf(s, "</feature>"); 305d12379c5SAlex Bennée cpu->dyn_svereg_xml.desc = g_string_free(s, false); 306d12379c5SAlex Bennée 307d12379c5SAlex Bennée return cpu->dyn_svereg_xml.num; 308d12379c5SAlex Bennée } 309d12379c5SAlex Bennée 310d12379c5SAlex Bennée 311200bf5b7SAbdallah Bouassida const char *arm_gdb_get_dynamic_xml(CPUState *cs, const char *xmlname) 312200bf5b7SAbdallah Bouassida { 313200bf5b7SAbdallah Bouassida ARMCPU *cpu = ARM_CPU(cs); 314200bf5b7SAbdallah Bouassida 315200bf5b7SAbdallah Bouassida if (strcmp(xmlname, "system-registers.xml") == 0) { 316448d4d14SAlex Bennée return cpu->dyn_sysreg_xml.desc; 317d12379c5SAlex Bennée } else if (strcmp(xmlname, "sve-registers.xml") == 0) { 318d12379c5SAlex Bennée return cpu->dyn_svereg_xml.desc; 319200bf5b7SAbdallah Bouassida } 320200bf5b7SAbdallah Bouassida return NULL; 321200bf5b7SAbdallah Bouassida } 322