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" 23cf7c6d10SRichard Henderson #include "internals.h" 24cf7c6d10SRichard Henderson #include "cpregs.h" 25fcf5ef2aSThomas Huth 26200bf5b7SAbdallah Bouassida typedef struct RegisterSysregXmlParam { 27200bf5b7SAbdallah Bouassida CPUState *cs; 28200bf5b7SAbdallah Bouassida GString *s; 2932d6e32aSAlex Bennée int n; 30200bf5b7SAbdallah Bouassida } RegisterSysregXmlParam; 31200bf5b7SAbdallah Bouassida 32fcf5ef2aSThomas Huth /* Old gdb always expect FPA registers. Newer (xml-aware) gdb only expect 33fcf5ef2aSThomas Huth whatever the target description contains. Due to a historical mishap 34fcf5ef2aSThomas Huth the FPA registers appear in between core integer regs and the CPSR. 35fcf5ef2aSThomas Huth We hack round this by giving the FPA regs zero size when talking to a 36fcf5ef2aSThomas Huth newer gdb. */ 37fcf5ef2aSThomas Huth 38a010bdbeSAlex Bennée int arm_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) 39fcf5ef2aSThomas Huth { 40fcf5ef2aSThomas Huth ARMCPU *cpu = ARM_CPU(cs); 41fcf5ef2aSThomas Huth CPUARMState *env = &cpu->env; 42fcf5ef2aSThomas Huth 43fcf5ef2aSThomas Huth if (n < 16) { 44fcf5ef2aSThomas Huth /* Core integer register. */ 45fcf5ef2aSThomas Huth return gdb_get_reg32(mem_buf, env->regs[n]); 46fcf5ef2aSThomas Huth } 47fcf5ef2aSThomas Huth if (n < 24) { 48fcf5ef2aSThomas Huth /* FPA registers. */ 49fcf5ef2aSThomas Huth if (gdb_has_xml) { 50fcf5ef2aSThomas Huth return 0; 51fcf5ef2aSThomas Huth } 527b8c1527SPhilippe Mathieu-Daudé return gdb_get_zeroes(mem_buf, 12); 53fcf5ef2aSThomas Huth } 54fcf5ef2aSThomas Huth switch (n) { 55fcf5ef2aSThomas Huth case 24: 56fcf5ef2aSThomas Huth /* FPA status register. */ 57fcf5ef2aSThomas Huth if (gdb_has_xml) { 58fcf5ef2aSThomas Huth return 0; 59fcf5ef2aSThomas Huth } 60fcf5ef2aSThomas Huth return gdb_get_reg32(mem_buf, 0); 61fcf5ef2aSThomas Huth case 25: 62c888f7e0SPeter Maydell /* CPSR, or XPSR for M-profile */ 63c888f7e0SPeter Maydell if (arm_feature(env, ARM_FEATURE_M)) { 64c888f7e0SPeter Maydell return gdb_get_reg32(mem_buf, xpsr_read(env)); 65c888f7e0SPeter Maydell } else { 66fcf5ef2aSThomas Huth return gdb_get_reg32(mem_buf, cpsr_read(env)); 67fcf5ef2aSThomas Huth } 68c888f7e0SPeter Maydell } 69fcf5ef2aSThomas Huth /* Unknown register. */ 70fcf5ef2aSThomas Huth return 0; 71fcf5ef2aSThomas Huth } 72fcf5ef2aSThomas Huth 73fcf5ef2aSThomas Huth int arm_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) 74fcf5ef2aSThomas Huth { 75fcf5ef2aSThomas Huth ARMCPU *cpu = ARM_CPU(cs); 76fcf5ef2aSThomas Huth CPUARMState *env = &cpu->env; 77fcf5ef2aSThomas Huth uint32_t tmp; 78fcf5ef2aSThomas Huth 79fcf5ef2aSThomas Huth tmp = ldl_p(mem_buf); 80fcf5ef2aSThomas Huth 817055fe4bSRichard Henderson /* 827055fe4bSRichard Henderson * Mask out low bits of PC to workaround gdb bugs. 837055fe4bSRichard Henderson * This avoids an assert in thumb_tr_translate_insn, because it is 847055fe4bSRichard Henderson * architecturally impossible to misalign the pc. 857055fe4bSRichard Henderson * This will probably cause problems if we ever implement the 867055fe4bSRichard Henderson * Jazelle DBX extensions. 877055fe4bSRichard Henderson */ 88fcf5ef2aSThomas Huth if (n == 15) { 89fcf5ef2aSThomas Huth tmp &= ~1; 90fcf5ef2aSThomas Huth } 91fcf5ef2aSThomas Huth 92fcf5ef2aSThomas Huth if (n < 16) { 93fcf5ef2aSThomas Huth /* Core integer register. */ 94888f470fSPeter Maydell if (n == 13 && arm_feature(env, ARM_FEATURE_M)) { 95888f470fSPeter Maydell /* M profile SP low bits are always 0 */ 96888f470fSPeter Maydell tmp &= ~3; 97888f470fSPeter Maydell } 98fcf5ef2aSThomas Huth env->regs[n] = tmp; 99fcf5ef2aSThomas Huth return 4; 100fcf5ef2aSThomas Huth } 101fcf5ef2aSThomas Huth if (n < 24) { /* 16-23 */ 102fcf5ef2aSThomas Huth /* FPA registers (ignored). */ 103fcf5ef2aSThomas Huth if (gdb_has_xml) { 104fcf5ef2aSThomas Huth return 0; 105fcf5ef2aSThomas Huth } 106fcf5ef2aSThomas Huth return 12; 107fcf5ef2aSThomas Huth } 108fcf5ef2aSThomas Huth switch (n) { 109fcf5ef2aSThomas Huth case 24: 110fcf5ef2aSThomas Huth /* FPA status register (ignored). */ 111fcf5ef2aSThomas Huth if (gdb_has_xml) { 112fcf5ef2aSThomas Huth return 0; 113fcf5ef2aSThomas Huth } 114fcf5ef2aSThomas Huth return 4; 115fcf5ef2aSThomas Huth case 25: 116c888f7e0SPeter Maydell /* CPSR, or XPSR for M-profile */ 117c888f7e0SPeter Maydell if (arm_feature(env, ARM_FEATURE_M)) { 118c888f7e0SPeter Maydell /* 119c888f7e0SPeter Maydell * Don't allow writing to XPSR.Exception as it can cause 120c888f7e0SPeter Maydell * a transition into or out of handler mode (it's not 1219323e79fSPeter Maydell * writable via the MSR insn so this is a reasonable 122c888f7e0SPeter Maydell * restriction). Other fields are safe to update. 123c888f7e0SPeter Maydell */ 124c888f7e0SPeter Maydell xpsr_write(env, tmp, ~XPSR_EXCP); 125c888f7e0SPeter Maydell } else { 126fcf5ef2aSThomas Huth cpsr_write(env, tmp, 0xffffffff, CPSRWriteByGDBStub); 127c888f7e0SPeter Maydell } 128fcf5ef2aSThomas Huth return 4; 129fcf5ef2aSThomas Huth } 130fcf5ef2aSThomas Huth /* Unknown register. */ 131fcf5ef2aSThomas Huth return 0; 132fcf5ef2aSThomas Huth } 133200bf5b7SAbdallah Bouassida 13489f4f20eSPeter Maydell static int vfp_gdb_get_reg(CPUARMState *env, GByteArray *buf, int reg) 13589f4f20eSPeter Maydell { 13689f4f20eSPeter Maydell ARMCPU *cpu = env_archcpu(env); 13789f4f20eSPeter Maydell int nregs = cpu_isar_feature(aa32_simd_r32, cpu) ? 32 : 16; 13889f4f20eSPeter Maydell 13989f4f20eSPeter Maydell /* VFP data registers are always little-endian. */ 14089f4f20eSPeter Maydell if (reg < nregs) { 14189f4f20eSPeter Maydell return gdb_get_reg64(buf, *aa32_vfp_dreg(env, reg)); 14289f4f20eSPeter Maydell } 14389f4f20eSPeter Maydell if (arm_feature(env, ARM_FEATURE_NEON)) { 14489f4f20eSPeter Maydell /* Aliases for Q regs. */ 14589f4f20eSPeter Maydell nregs += 16; 14689f4f20eSPeter Maydell if (reg < nregs) { 14789f4f20eSPeter Maydell uint64_t *q = aa32_vfp_qreg(env, reg - 32); 14889f4f20eSPeter Maydell return gdb_get_reg128(buf, q[0], q[1]); 14989f4f20eSPeter Maydell } 15089f4f20eSPeter Maydell } 15189f4f20eSPeter Maydell switch (reg - nregs) { 15289f4f20eSPeter Maydell case 0: 15389f4f20eSPeter Maydell return gdb_get_reg32(buf, vfp_get_fpscr(env)); 15489f4f20eSPeter Maydell } 15589f4f20eSPeter Maydell return 0; 15689f4f20eSPeter Maydell } 15789f4f20eSPeter Maydell 15889f4f20eSPeter Maydell static int vfp_gdb_set_reg(CPUARMState *env, uint8_t *buf, int reg) 15989f4f20eSPeter Maydell { 16089f4f20eSPeter Maydell ARMCPU *cpu = env_archcpu(env); 16189f4f20eSPeter Maydell int nregs = cpu_isar_feature(aa32_simd_r32, cpu) ? 32 : 16; 16289f4f20eSPeter Maydell 16389f4f20eSPeter Maydell if (reg < nregs) { 16489f4f20eSPeter Maydell *aa32_vfp_dreg(env, reg) = ldq_le_p(buf); 16589f4f20eSPeter Maydell return 8; 16689f4f20eSPeter Maydell } 16789f4f20eSPeter Maydell if (arm_feature(env, ARM_FEATURE_NEON)) { 16889f4f20eSPeter Maydell nregs += 16; 16989f4f20eSPeter Maydell if (reg < nregs) { 17089f4f20eSPeter Maydell uint64_t *q = aa32_vfp_qreg(env, reg - 32); 17189f4f20eSPeter Maydell q[0] = ldq_le_p(buf); 17289f4f20eSPeter Maydell q[1] = ldq_le_p(buf + 8); 17389f4f20eSPeter Maydell return 16; 17489f4f20eSPeter Maydell } 17589f4f20eSPeter Maydell } 17689f4f20eSPeter Maydell switch (reg - nregs) { 17789f4f20eSPeter Maydell case 0: 178b355f08aSPeter Maydell vfp_set_fpscr(env, ldl_p(buf)); 179b355f08aSPeter Maydell return 4; 180b355f08aSPeter Maydell } 181b355f08aSPeter Maydell return 0; 182b355f08aSPeter Maydell } 183b355f08aSPeter Maydell 184b355f08aSPeter Maydell static int vfp_gdb_get_sysreg(CPUARMState *env, GByteArray *buf, int reg) 185b355f08aSPeter Maydell { 186b355f08aSPeter Maydell switch (reg) { 187b355f08aSPeter Maydell case 0: 188b355f08aSPeter Maydell return gdb_get_reg32(buf, env->vfp.xregs[ARM_VFP_FPSID]); 189b355f08aSPeter Maydell case 1: 190b355f08aSPeter Maydell return gdb_get_reg32(buf, env->vfp.xregs[ARM_VFP_FPEXC]); 191b355f08aSPeter Maydell } 192b355f08aSPeter Maydell return 0; 193b355f08aSPeter Maydell } 194b355f08aSPeter Maydell 195b355f08aSPeter Maydell static int vfp_gdb_set_sysreg(CPUARMState *env, uint8_t *buf, int reg) 196b355f08aSPeter Maydell { 197b355f08aSPeter Maydell switch (reg) { 198b355f08aSPeter Maydell case 0: 19989f4f20eSPeter Maydell env->vfp.xregs[ARM_VFP_FPSID] = ldl_p(buf); 20089f4f20eSPeter Maydell return 4; 20189f4f20eSPeter Maydell case 1: 20289f4f20eSPeter Maydell env->vfp.xregs[ARM_VFP_FPEXC] = ldl_p(buf) & (1 << 30); 20389f4f20eSPeter Maydell return 4; 20489f4f20eSPeter Maydell } 20589f4f20eSPeter Maydell return 0; 20689f4f20eSPeter Maydell } 20789f4f20eSPeter Maydell 208dbd9e084SPeter Maydell static int mve_gdb_get_reg(CPUARMState *env, GByteArray *buf, int reg) 209dbd9e084SPeter Maydell { 210dbd9e084SPeter Maydell switch (reg) { 211dbd9e084SPeter Maydell case 0: 212dbd9e084SPeter Maydell return gdb_get_reg32(buf, env->v7m.vpr); 213dbd9e084SPeter Maydell default: 214dbd9e084SPeter Maydell return 0; 215dbd9e084SPeter Maydell } 216dbd9e084SPeter Maydell } 217dbd9e084SPeter Maydell 218dbd9e084SPeter Maydell static int mve_gdb_set_reg(CPUARMState *env, uint8_t *buf, int reg) 219dbd9e084SPeter Maydell { 220dbd9e084SPeter Maydell switch (reg) { 221dbd9e084SPeter Maydell case 0: 222dbd9e084SPeter Maydell env->v7m.vpr = ldl_p(buf); 223dbd9e084SPeter Maydell return 4; 224dbd9e084SPeter Maydell default: 225dbd9e084SPeter Maydell return 0; 226dbd9e084SPeter Maydell } 227dbd9e084SPeter Maydell } 228dbd9e084SPeter Maydell 22989f4f20eSPeter Maydell /** 23089f4f20eSPeter Maydell * arm_get/set_gdb_*: get/set a gdb register 23189f4f20eSPeter Maydell * @env: the CPU state 23289f4f20eSPeter Maydell * @buf: a buffer to copy to/from 23389f4f20eSPeter Maydell * @reg: register number (offset from start of group) 23489f4f20eSPeter Maydell * 23589f4f20eSPeter Maydell * We return the number of bytes copied 23689f4f20eSPeter Maydell */ 23789f4f20eSPeter Maydell 23889f4f20eSPeter Maydell static int arm_gdb_get_sysreg(CPUARMState *env, GByteArray *buf, int reg) 23989f4f20eSPeter Maydell { 24089f4f20eSPeter Maydell ARMCPU *cpu = env_archcpu(env); 24189f4f20eSPeter Maydell const ARMCPRegInfo *ri; 24289f4f20eSPeter Maydell uint32_t key; 24389f4f20eSPeter Maydell 24489f4f20eSPeter Maydell key = cpu->dyn_sysreg_xml.data.cpregs.keys[reg]; 24589f4f20eSPeter Maydell ri = get_arm_cp_reginfo(cpu->cp_regs, key); 24689f4f20eSPeter Maydell if (ri) { 24789f4f20eSPeter Maydell if (cpreg_field_is_64bit(ri)) { 24889f4f20eSPeter Maydell return gdb_get_reg64(buf, (uint64_t)read_raw_cp_reg(env, ri)); 24989f4f20eSPeter Maydell } else { 25089f4f20eSPeter Maydell return gdb_get_reg32(buf, (uint32_t)read_raw_cp_reg(env, ri)); 25189f4f20eSPeter Maydell } 25289f4f20eSPeter Maydell } 25389f4f20eSPeter Maydell return 0; 25489f4f20eSPeter Maydell } 25589f4f20eSPeter Maydell 25689f4f20eSPeter Maydell static int arm_gdb_set_sysreg(CPUARMState *env, uint8_t *buf, int reg) 25789f4f20eSPeter Maydell { 25889f4f20eSPeter Maydell return 0; 25989f4f20eSPeter Maydell } 26089f4f20eSPeter Maydell 261448d4d14SAlex Bennée static void arm_gen_one_xml_sysreg_tag(GString *s, DynamicGDBXMLInfo *dyn_xml, 262200bf5b7SAbdallah Bouassida ARMCPRegInfo *ri, uint32_t ri_key, 26332d6e32aSAlex Bennée int bitsize, int regnum) 264200bf5b7SAbdallah Bouassida { 265200bf5b7SAbdallah Bouassida g_string_append_printf(s, "<reg name=\"%s\"", ri->name); 266200bf5b7SAbdallah Bouassida g_string_append_printf(s, " bitsize=\"%d\"", bitsize); 26732d6e32aSAlex Bennée g_string_append_printf(s, " regnum=\"%d\"", regnum); 268200bf5b7SAbdallah Bouassida g_string_append_printf(s, " group=\"cp_regs\"/>"); 269448d4d14SAlex Bennée dyn_xml->data.cpregs.keys[dyn_xml->num] = ri_key; 270448d4d14SAlex Bennée dyn_xml->num++; 271200bf5b7SAbdallah Bouassida } 272200bf5b7SAbdallah Bouassida 273200bf5b7SAbdallah Bouassida static void arm_register_sysreg_for_xml(gpointer key, gpointer value, 274200bf5b7SAbdallah Bouassida gpointer p) 275200bf5b7SAbdallah Bouassida { 2765860362dSRichard Henderson uint32_t ri_key = (uintptr_t)key; 277200bf5b7SAbdallah Bouassida ARMCPRegInfo *ri = value; 278200bf5b7SAbdallah Bouassida RegisterSysregXmlParam *param = (RegisterSysregXmlParam *)p; 279200bf5b7SAbdallah Bouassida GString *s = param->s; 280200bf5b7SAbdallah Bouassida ARMCPU *cpu = ARM_CPU(param->cs); 281200bf5b7SAbdallah Bouassida CPUARMState *env = &cpu->env; 282448d4d14SAlex Bennée DynamicGDBXMLInfo *dyn_xml = &cpu->dyn_sysreg_xml; 283200bf5b7SAbdallah Bouassida 284200bf5b7SAbdallah Bouassida if (!(ri->type & (ARM_CP_NO_RAW | ARM_CP_NO_GDB))) { 285200bf5b7SAbdallah Bouassida if (arm_feature(env, ARM_FEATURE_AARCH64)) { 286200bf5b7SAbdallah Bouassida if (ri->state == ARM_CP_STATE_AA64) { 28732d6e32aSAlex Bennée arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 64, 28832d6e32aSAlex Bennée param->n++); 289200bf5b7SAbdallah Bouassida } 290200bf5b7SAbdallah Bouassida } else { 291200bf5b7SAbdallah Bouassida if (ri->state == ARM_CP_STATE_AA32) { 292200bf5b7SAbdallah Bouassida if (!arm_feature(env, ARM_FEATURE_EL3) && 293200bf5b7SAbdallah Bouassida (ri->secure & ARM_CP_SECSTATE_S)) { 294200bf5b7SAbdallah Bouassida return; 295200bf5b7SAbdallah Bouassida } 296200bf5b7SAbdallah Bouassida if (ri->type & ARM_CP_64BIT) { 29732d6e32aSAlex Bennée arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 64, 29832d6e32aSAlex Bennée param->n++); 299200bf5b7SAbdallah Bouassida } else { 30032d6e32aSAlex Bennée arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 32, 30132d6e32aSAlex Bennée param->n++); 302200bf5b7SAbdallah Bouassida } 303200bf5b7SAbdallah Bouassida } 304200bf5b7SAbdallah Bouassida } 305200bf5b7SAbdallah Bouassida } 306200bf5b7SAbdallah Bouassida } 307200bf5b7SAbdallah Bouassida 3084bce95b4SRichard Henderson static int arm_gen_dynamic_sysreg_xml(CPUState *cs, int base_reg) 309200bf5b7SAbdallah Bouassida { 310200bf5b7SAbdallah Bouassida ARMCPU *cpu = ARM_CPU(cs); 311200bf5b7SAbdallah Bouassida GString *s = g_string_new(NULL); 31232d6e32aSAlex Bennée RegisterSysregXmlParam param = {cs, s, base_reg}; 313200bf5b7SAbdallah Bouassida 314448d4d14SAlex Bennée cpu->dyn_sysreg_xml.num = 0; 315448d4d14SAlex Bennée cpu->dyn_sysreg_xml.data.cpregs.keys = g_new(uint32_t, g_hash_table_size(cpu->cp_regs)); 316200bf5b7SAbdallah Bouassida g_string_printf(s, "<?xml version=\"1.0\"?>"); 317200bf5b7SAbdallah Bouassida g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">"); 318200bf5b7SAbdallah Bouassida g_string_append_printf(s, "<feature name=\"org.qemu.gdb.arm.sys.regs\">"); 319200bf5b7SAbdallah Bouassida g_hash_table_foreach(cpu->cp_regs, arm_register_sysreg_for_xml, ¶m); 320200bf5b7SAbdallah Bouassida g_string_append_printf(s, "</feature>"); 321448d4d14SAlex Bennée cpu->dyn_sysreg_xml.desc = g_string_free(s, false); 322448d4d14SAlex Bennée return cpu->dyn_sysreg_xml.num; 323200bf5b7SAbdallah Bouassida } 324200bf5b7SAbdallah Bouassida 325*7d8b28b8SRichard Henderson typedef enum { 326*7d8b28b8SRichard Henderson M_SYSREG_MSP, 327*7d8b28b8SRichard Henderson M_SYSREG_PSP, 328*7d8b28b8SRichard Henderson M_SYSREG_PRIMASK, 329*7d8b28b8SRichard Henderson M_SYSREG_CONTROL, 330*7d8b28b8SRichard Henderson M_SYSREG_BASEPRI, 331*7d8b28b8SRichard Henderson M_SYSREG_FAULTMASK, 332*7d8b28b8SRichard Henderson M_SYSREG_MSPLIM, 333*7d8b28b8SRichard Henderson M_SYSREG_PSPLIM, 334*7d8b28b8SRichard Henderson } MProfileSysreg; 335*7d8b28b8SRichard Henderson 336*7d8b28b8SRichard Henderson static const struct { 337*7d8b28b8SRichard Henderson const char *name; 338*7d8b28b8SRichard Henderson int feature; 339*7d8b28b8SRichard Henderson } m_sysreg_def[] = { 340*7d8b28b8SRichard Henderson [M_SYSREG_MSP] = { "msp", ARM_FEATURE_M }, 341*7d8b28b8SRichard Henderson [M_SYSREG_PSP] = { "psp", ARM_FEATURE_M }, 342*7d8b28b8SRichard Henderson [M_SYSREG_PRIMASK] = { "primask", ARM_FEATURE_M }, 343*7d8b28b8SRichard Henderson [M_SYSREG_CONTROL] = { "control", ARM_FEATURE_M }, 344*7d8b28b8SRichard Henderson [M_SYSREG_BASEPRI] = { "basepri", ARM_FEATURE_M_MAIN }, 345*7d8b28b8SRichard Henderson [M_SYSREG_FAULTMASK] = { "faultmask", ARM_FEATURE_M_MAIN }, 346*7d8b28b8SRichard Henderson [M_SYSREG_MSPLIM] = { "msplim", ARM_FEATURE_V8 }, 347*7d8b28b8SRichard Henderson [M_SYSREG_PSPLIM] = { "psplim", ARM_FEATURE_V8 }, 348*7d8b28b8SRichard Henderson }; 349*7d8b28b8SRichard Henderson 350*7d8b28b8SRichard Henderson static uint32_t *m_sysreg_ptr(CPUARMState *env, MProfileSysreg reg, bool sec) 351*7d8b28b8SRichard Henderson { 352*7d8b28b8SRichard Henderson uint32_t *ptr; 353*7d8b28b8SRichard Henderson 354*7d8b28b8SRichard Henderson switch (reg) { 355*7d8b28b8SRichard Henderson case M_SYSREG_MSP: 356*7d8b28b8SRichard Henderson ptr = arm_v7m_get_sp_ptr(env, sec, false, true); 357*7d8b28b8SRichard Henderson break; 358*7d8b28b8SRichard Henderson case M_SYSREG_PSP: 359*7d8b28b8SRichard Henderson ptr = arm_v7m_get_sp_ptr(env, sec, true, true); 360*7d8b28b8SRichard Henderson break; 361*7d8b28b8SRichard Henderson case M_SYSREG_MSPLIM: 362*7d8b28b8SRichard Henderson ptr = &env->v7m.msplim[sec]; 363*7d8b28b8SRichard Henderson break; 364*7d8b28b8SRichard Henderson case M_SYSREG_PSPLIM: 365*7d8b28b8SRichard Henderson ptr = &env->v7m.psplim[sec]; 366*7d8b28b8SRichard Henderson break; 367*7d8b28b8SRichard Henderson case M_SYSREG_PRIMASK: 368*7d8b28b8SRichard Henderson ptr = &env->v7m.primask[sec]; 369*7d8b28b8SRichard Henderson break; 370*7d8b28b8SRichard Henderson case M_SYSREG_BASEPRI: 371*7d8b28b8SRichard Henderson ptr = &env->v7m.basepri[sec]; 372*7d8b28b8SRichard Henderson break; 373*7d8b28b8SRichard Henderson case M_SYSREG_FAULTMASK: 374*7d8b28b8SRichard Henderson ptr = &env->v7m.faultmask[sec]; 375*7d8b28b8SRichard Henderson break; 376*7d8b28b8SRichard Henderson case M_SYSREG_CONTROL: 377*7d8b28b8SRichard Henderson ptr = &env->v7m.control[sec]; 378*7d8b28b8SRichard Henderson break; 379*7d8b28b8SRichard Henderson default: 380*7d8b28b8SRichard Henderson return NULL; 381*7d8b28b8SRichard Henderson } 382*7d8b28b8SRichard Henderson return arm_feature(env, m_sysreg_def[reg].feature) ? ptr : NULL; 383*7d8b28b8SRichard Henderson } 384*7d8b28b8SRichard Henderson 385*7d8b28b8SRichard Henderson static int m_sysreg_get(CPUARMState *env, GByteArray *buf, 386*7d8b28b8SRichard Henderson MProfileSysreg reg, bool secure) 387*7d8b28b8SRichard Henderson { 388*7d8b28b8SRichard Henderson uint32_t *ptr = m_sysreg_ptr(env, reg, secure); 389*7d8b28b8SRichard Henderson 390*7d8b28b8SRichard Henderson if (ptr == NULL) { 391*7d8b28b8SRichard Henderson return 0; 392*7d8b28b8SRichard Henderson } 393*7d8b28b8SRichard Henderson return gdb_get_reg32(buf, *ptr); 394*7d8b28b8SRichard Henderson } 395*7d8b28b8SRichard Henderson 396*7d8b28b8SRichard Henderson static int arm_gdb_get_m_systemreg(CPUARMState *env, GByteArray *buf, int reg) 397*7d8b28b8SRichard Henderson { 398*7d8b28b8SRichard Henderson /* 399*7d8b28b8SRichard Henderson * Here, we emulate MRS instruction, where CONTROL has a mix of 400*7d8b28b8SRichard Henderson * banked and non-banked bits. 401*7d8b28b8SRichard Henderson */ 402*7d8b28b8SRichard Henderson if (reg == M_SYSREG_CONTROL) { 403*7d8b28b8SRichard Henderson return gdb_get_reg32(buf, arm_v7m_mrs_control(env, env->v7m.secure)); 404*7d8b28b8SRichard Henderson } 405*7d8b28b8SRichard Henderson return m_sysreg_get(env, buf, reg, env->v7m.secure); 406*7d8b28b8SRichard Henderson } 407*7d8b28b8SRichard Henderson 408*7d8b28b8SRichard Henderson static int arm_gdb_set_m_systemreg(CPUARMState *env, uint8_t *buf, int reg) 409*7d8b28b8SRichard Henderson { 410*7d8b28b8SRichard Henderson return 0; /* TODO */ 411*7d8b28b8SRichard Henderson } 412*7d8b28b8SRichard Henderson 413*7d8b28b8SRichard Henderson static int arm_gen_dynamic_m_systemreg_xml(CPUState *cs, int orig_base_reg) 414*7d8b28b8SRichard Henderson { 415*7d8b28b8SRichard Henderson ARMCPU *cpu = ARM_CPU(cs); 416*7d8b28b8SRichard Henderson CPUARMState *env = &cpu->env; 417*7d8b28b8SRichard Henderson GString *s = g_string_new(NULL); 418*7d8b28b8SRichard Henderson int base_reg = orig_base_reg; 419*7d8b28b8SRichard Henderson int i; 420*7d8b28b8SRichard Henderson 421*7d8b28b8SRichard Henderson g_string_printf(s, "<?xml version=\"1.0\"?>"); 422*7d8b28b8SRichard Henderson g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">"); 423*7d8b28b8SRichard Henderson g_string_append_printf(s, "<feature name=\"org.gnu.gdb.arm.m-system\">\n"); 424*7d8b28b8SRichard Henderson 425*7d8b28b8SRichard Henderson for (i = 0; i < ARRAY_SIZE(m_sysreg_def); i++) { 426*7d8b28b8SRichard Henderson if (arm_feature(env, m_sysreg_def[i].feature)) { 427*7d8b28b8SRichard Henderson g_string_append_printf(s, 428*7d8b28b8SRichard Henderson "<reg name=\"%s\" bitsize=\"32\" regnum=\"%d\"/>\n", 429*7d8b28b8SRichard Henderson m_sysreg_def[i].name, base_reg++); 430*7d8b28b8SRichard Henderson } 431*7d8b28b8SRichard Henderson } 432*7d8b28b8SRichard Henderson 433*7d8b28b8SRichard Henderson g_string_append_printf(s, "</feature>"); 434*7d8b28b8SRichard Henderson cpu->dyn_m_systemreg_xml.desc = g_string_free(s, false); 435*7d8b28b8SRichard Henderson cpu->dyn_m_systemreg_xml.num = base_reg - orig_base_reg; 436*7d8b28b8SRichard Henderson 437*7d8b28b8SRichard Henderson return cpu->dyn_m_systemreg_xml.num; 438*7d8b28b8SRichard Henderson } 439*7d8b28b8SRichard Henderson 440*7d8b28b8SRichard Henderson #ifndef CONFIG_USER_ONLY 441*7d8b28b8SRichard Henderson /* 442*7d8b28b8SRichard Henderson * For user-only, we see the non-secure registers via m_systemreg above. 443*7d8b28b8SRichard Henderson * For secext, encode the non-secure view as even and secure view as odd. 444*7d8b28b8SRichard Henderson */ 445*7d8b28b8SRichard Henderson static int arm_gdb_get_m_secextreg(CPUARMState *env, GByteArray *buf, int reg) 446*7d8b28b8SRichard Henderson { 447*7d8b28b8SRichard Henderson return m_sysreg_get(env, buf, reg >> 1, reg & 1); 448*7d8b28b8SRichard Henderson } 449*7d8b28b8SRichard Henderson 450*7d8b28b8SRichard Henderson static int arm_gdb_set_m_secextreg(CPUARMState *env, uint8_t *buf, int reg) 451*7d8b28b8SRichard Henderson { 452*7d8b28b8SRichard Henderson return 0; /* TODO */ 453*7d8b28b8SRichard Henderson } 454*7d8b28b8SRichard Henderson 455*7d8b28b8SRichard Henderson static int arm_gen_dynamic_m_secextreg_xml(CPUState *cs, int orig_base_reg) 456*7d8b28b8SRichard Henderson { 457*7d8b28b8SRichard Henderson ARMCPU *cpu = ARM_CPU(cs); 458*7d8b28b8SRichard Henderson GString *s = g_string_new(NULL); 459*7d8b28b8SRichard Henderson int base_reg = orig_base_reg; 460*7d8b28b8SRichard Henderson int i; 461*7d8b28b8SRichard Henderson 462*7d8b28b8SRichard Henderson g_string_printf(s, "<?xml version=\"1.0\"?>"); 463*7d8b28b8SRichard Henderson g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">"); 464*7d8b28b8SRichard Henderson g_string_append_printf(s, "<feature name=\"org.gnu.gdb.arm.secext\">\n"); 465*7d8b28b8SRichard Henderson 466*7d8b28b8SRichard Henderson for (i = 0; i < ARRAY_SIZE(m_sysreg_def); i++) { 467*7d8b28b8SRichard Henderson g_string_append_printf(s, 468*7d8b28b8SRichard Henderson "<reg name=\"%s_ns\" bitsize=\"32\" regnum=\"%d\"/>\n", 469*7d8b28b8SRichard Henderson m_sysreg_def[i].name, base_reg++); 470*7d8b28b8SRichard Henderson g_string_append_printf(s, 471*7d8b28b8SRichard Henderson "<reg name=\"%s_s\" bitsize=\"32\" regnum=\"%d\"/>\n", 472*7d8b28b8SRichard Henderson m_sysreg_def[i].name, base_reg++); 473*7d8b28b8SRichard Henderson } 474*7d8b28b8SRichard Henderson 475*7d8b28b8SRichard Henderson g_string_append_printf(s, "</feature>"); 476*7d8b28b8SRichard Henderson cpu->dyn_m_secextreg_xml.desc = g_string_free(s, false); 477*7d8b28b8SRichard Henderson cpu->dyn_m_secextreg_xml.num = base_reg - orig_base_reg; 478*7d8b28b8SRichard Henderson 479*7d8b28b8SRichard Henderson return cpu->dyn_m_secextreg_xml.num; 480*7d8b28b8SRichard Henderson } 481*7d8b28b8SRichard Henderson #endif 482*7d8b28b8SRichard Henderson 483200bf5b7SAbdallah Bouassida const char *arm_gdb_get_dynamic_xml(CPUState *cs, const char *xmlname) 484200bf5b7SAbdallah Bouassida { 485200bf5b7SAbdallah Bouassida ARMCPU *cpu = ARM_CPU(cs); 486200bf5b7SAbdallah Bouassida 487200bf5b7SAbdallah Bouassida if (strcmp(xmlname, "system-registers.xml") == 0) { 488448d4d14SAlex Bennée return cpu->dyn_sysreg_xml.desc; 489d12379c5SAlex Bennée } else if (strcmp(xmlname, "sve-registers.xml") == 0) { 490d12379c5SAlex Bennée return cpu->dyn_svereg_xml.desc; 491*7d8b28b8SRichard Henderson } else if (strcmp(xmlname, "arm-m-system.xml") == 0) { 492*7d8b28b8SRichard Henderson return cpu->dyn_m_systemreg_xml.desc; 493*7d8b28b8SRichard Henderson #ifndef CONFIG_USER_ONLY 494*7d8b28b8SRichard Henderson } else if (strcmp(xmlname, "arm-m-secext.xml") == 0) { 495*7d8b28b8SRichard Henderson return cpu->dyn_m_secextreg_xml.desc; 496*7d8b28b8SRichard Henderson #endif 497200bf5b7SAbdallah Bouassida } 498200bf5b7SAbdallah Bouassida return NULL; 499200bf5b7SAbdallah Bouassida } 50089f4f20eSPeter Maydell 50189f4f20eSPeter Maydell void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu) 50289f4f20eSPeter Maydell { 50389f4f20eSPeter Maydell CPUState *cs = CPU(cpu); 50489f4f20eSPeter Maydell CPUARMState *env = &cpu->env; 50589f4f20eSPeter Maydell 50689f4f20eSPeter Maydell if (arm_feature(env, ARM_FEATURE_AARCH64)) { 50789f4f20eSPeter Maydell /* 50889f4f20eSPeter Maydell * The lower part of each SVE register aliases to the FPU 50989f4f20eSPeter Maydell * registers so we don't need to include both. 51089f4f20eSPeter Maydell */ 51189f4f20eSPeter Maydell #ifdef TARGET_AARCH64 51289f4f20eSPeter Maydell if (isar_feature_aa64_sve(&cpu->isar)) { 513963a6b91SRichard Henderson int nreg = arm_gen_dynamic_svereg_xml(cs, cs->gdb_num_regs); 514963a6b91SRichard Henderson gdb_register_coprocessor(cs, aarch64_gdb_get_sve_reg, 515963a6b91SRichard Henderson aarch64_gdb_set_sve_reg, nreg, 51689f4f20eSPeter Maydell "sve-registers.xml", 0); 51789f4f20eSPeter Maydell } else { 518963a6b91SRichard Henderson gdb_register_coprocessor(cs, aarch64_gdb_get_fpu_reg, 519963a6b91SRichard Henderson aarch64_gdb_set_fpu_reg, 52089f4f20eSPeter Maydell 34, "aarch64-fpu.xml", 0); 52189f4f20eSPeter Maydell } 522e995d5ccSRichard Henderson if (isar_feature_aa64_pauth(&cpu->isar)) { 523e995d5ccSRichard Henderson gdb_register_coprocessor(cs, aarch64_gdb_get_pauth_reg, 524e995d5ccSRichard Henderson aarch64_gdb_set_pauth_reg, 525e995d5ccSRichard Henderson 4, "aarch64-pauth.xml", 0); 526e995d5ccSRichard Henderson } 52789f4f20eSPeter Maydell #endif 528b355f08aSPeter Maydell } else { 529b355f08aSPeter Maydell if (arm_feature(env, ARM_FEATURE_NEON)) { 53089f4f20eSPeter Maydell gdb_register_coprocessor(cs, vfp_gdb_get_reg, vfp_gdb_set_reg, 531b355f08aSPeter Maydell 49, "arm-neon.xml", 0); 53289f4f20eSPeter Maydell } else if (cpu_isar_feature(aa32_simd_r32, cpu)) { 53389f4f20eSPeter Maydell gdb_register_coprocessor(cs, vfp_gdb_get_reg, vfp_gdb_set_reg, 534b355f08aSPeter Maydell 33, "arm-vfp3.xml", 0); 53589f4f20eSPeter Maydell } else if (cpu_isar_feature(aa32_vfp_simd, cpu)) { 53689f4f20eSPeter Maydell gdb_register_coprocessor(cs, vfp_gdb_get_reg, vfp_gdb_set_reg, 537b355f08aSPeter Maydell 17, "arm-vfp.xml", 0); 538b355f08aSPeter Maydell } 539b355f08aSPeter Maydell if (!arm_feature(env, ARM_FEATURE_M)) { 540b355f08aSPeter Maydell /* 541b355f08aSPeter Maydell * A and R profile have FP sysregs FPEXC and FPSID that we 542b355f08aSPeter Maydell * expose to gdb. 543b355f08aSPeter Maydell */ 544b355f08aSPeter Maydell gdb_register_coprocessor(cs, vfp_gdb_get_sysreg, vfp_gdb_set_sysreg, 545b355f08aSPeter Maydell 2, "arm-vfp-sysregs.xml", 0); 546b355f08aSPeter Maydell } 54789f4f20eSPeter Maydell } 548dbd9e084SPeter Maydell if (cpu_isar_feature(aa32_mve, cpu)) { 549dbd9e084SPeter Maydell gdb_register_coprocessor(cs, mve_gdb_get_reg, mve_gdb_set_reg, 550dbd9e084SPeter Maydell 1, "arm-m-profile-mve.xml", 0); 551dbd9e084SPeter Maydell } 55289f4f20eSPeter Maydell gdb_register_coprocessor(cs, arm_gdb_get_sysreg, arm_gdb_set_sysreg, 55389f4f20eSPeter Maydell arm_gen_dynamic_sysreg_xml(cs, cs->gdb_num_regs), 55489f4f20eSPeter Maydell "system-registers.xml", 0); 55589f4f20eSPeter Maydell 556*7d8b28b8SRichard Henderson if (arm_feature(env, ARM_FEATURE_M)) { 557*7d8b28b8SRichard Henderson gdb_register_coprocessor(cs, 558*7d8b28b8SRichard Henderson arm_gdb_get_m_systemreg, arm_gdb_set_m_systemreg, 559*7d8b28b8SRichard Henderson arm_gen_dynamic_m_systemreg_xml(cs, cs->gdb_num_regs), 560*7d8b28b8SRichard Henderson "arm-m-system.xml", 0); 561*7d8b28b8SRichard Henderson #ifndef CONFIG_USER_ONLY 562*7d8b28b8SRichard Henderson if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { 563*7d8b28b8SRichard Henderson gdb_register_coprocessor(cs, 564*7d8b28b8SRichard Henderson arm_gdb_get_m_secextreg, arm_gdb_set_m_secextreg, 565*7d8b28b8SRichard Henderson arm_gen_dynamic_m_secextreg_xml(cs, cs->gdb_num_regs), 566*7d8b28b8SRichard Henderson "arm-m-secext.xml", 0); 567*7d8b28b8SRichard Henderson } 568*7d8b28b8SRichard Henderson #endif 569*7d8b28b8SRichard Henderson } 57089f4f20eSPeter Maydell } 571