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" 234ea5fe99SAlex Bennée #include "gdbstub/helpers.h" 24cf7c6d10SRichard Henderson #include "internals.h" 25cf7c6d10SRichard Henderson #include "cpregs.h" 26fcf5ef2aSThomas Huth 27200bf5b7SAbdallah Bouassida typedef struct RegisterSysregXmlParam { 28200bf5b7SAbdallah Bouassida CPUState *cs; 29200bf5b7SAbdallah Bouassida GString *s; 3032d6e32aSAlex Bennée int n; 31200bf5b7SAbdallah Bouassida } RegisterSysregXmlParam; 32200bf5b7SAbdallah Bouassida 33fcf5ef2aSThomas Huth /* Old gdb always expect FPA registers. Newer (xml-aware) gdb only expect 34fcf5ef2aSThomas Huth whatever the target description contains. Due to a historical mishap 35fcf5ef2aSThomas Huth the FPA registers appear in between core integer regs and the CPSR. 36fcf5ef2aSThomas Huth We hack round this by giving the FPA regs zero size when talking to a 37fcf5ef2aSThomas Huth newer gdb. */ 38fcf5ef2aSThomas Huth 39a010bdbeSAlex Bennée int arm_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) 40fcf5ef2aSThomas Huth { 41fcf5ef2aSThomas Huth ARMCPU *cpu = ARM_CPU(cs); 42fcf5ef2aSThomas Huth CPUARMState *env = &cpu->env; 43fcf5ef2aSThomas Huth 44fcf5ef2aSThomas Huth if (n < 16) { 45fcf5ef2aSThomas Huth /* Core integer register. */ 46fcf5ef2aSThomas Huth return gdb_get_reg32(mem_buf, env->regs[n]); 47fcf5ef2aSThomas Huth } 48fcf5ef2aSThomas Huth if (n < 24) { 49fcf5ef2aSThomas Huth /* FPA registers. */ 50fcf5ef2aSThomas Huth if (gdb_has_xml) { 51fcf5ef2aSThomas Huth return 0; 52fcf5ef2aSThomas Huth } 537b8c1527SPhilippe Mathieu-Daudé return gdb_get_zeroes(mem_buf, 12); 54fcf5ef2aSThomas Huth } 55fcf5ef2aSThomas Huth switch (n) { 56fcf5ef2aSThomas Huth case 24: 57fcf5ef2aSThomas Huth /* FPA status register. */ 58fcf5ef2aSThomas Huth if (gdb_has_xml) { 59fcf5ef2aSThomas Huth return 0; 60fcf5ef2aSThomas Huth } 61fcf5ef2aSThomas Huth return gdb_get_reg32(mem_buf, 0); 62fcf5ef2aSThomas Huth case 25: 63c888f7e0SPeter Maydell /* CPSR, or XPSR for M-profile */ 64c888f7e0SPeter Maydell if (arm_feature(env, ARM_FEATURE_M)) { 65c888f7e0SPeter Maydell return gdb_get_reg32(mem_buf, xpsr_read(env)); 66c888f7e0SPeter Maydell } else { 67fcf5ef2aSThomas Huth return gdb_get_reg32(mem_buf, cpsr_read(env)); 68fcf5ef2aSThomas Huth } 69c888f7e0SPeter Maydell } 70fcf5ef2aSThomas Huth /* Unknown register. */ 71fcf5ef2aSThomas Huth return 0; 72fcf5ef2aSThomas Huth } 73fcf5ef2aSThomas Huth 74fcf5ef2aSThomas Huth int arm_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) 75fcf5ef2aSThomas Huth { 76fcf5ef2aSThomas Huth ARMCPU *cpu = ARM_CPU(cs); 77fcf5ef2aSThomas Huth CPUARMState *env = &cpu->env; 78fcf5ef2aSThomas Huth uint32_t tmp; 79fcf5ef2aSThomas Huth 80fcf5ef2aSThomas Huth tmp = ldl_p(mem_buf); 81fcf5ef2aSThomas Huth 827055fe4bSRichard Henderson /* 837055fe4bSRichard Henderson * Mask out low bits of PC to workaround gdb bugs. 847055fe4bSRichard Henderson * This avoids an assert in thumb_tr_translate_insn, because it is 857055fe4bSRichard Henderson * architecturally impossible to misalign the pc. 867055fe4bSRichard Henderson * This will probably cause problems if we ever implement the 877055fe4bSRichard Henderson * Jazelle DBX extensions. 887055fe4bSRichard Henderson */ 89fcf5ef2aSThomas Huth if (n == 15) { 90fcf5ef2aSThomas Huth tmp &= ~1; 91fcf5ef2aSThomas Huth } 92fcf5ef2aSThomas Huth 93fcf5ef2aSThomas Huth if (n < 16) { 94fcf5ef2aSThomas Huth /* Core integer register. */ 95888f470fSPeter Maydell if (n == 13 && arm_feature(env, ARM_FEATURE_M)) { 96888f470fSPeter Maydell /* M profile SP low bits are always 0 */ 97888f470fSPeter Maydell tmp &= ~3; 98888f470fSPeter Maydell } 99fcf5ef2aSThomas Huth env->regs[n] = tmp; 100fcf5ef2aSThomas Huth return 4; 101fcf5ef2aSThomas Huth } 102fcf5ef2aSThomas Huth if (n < 24) { /* 16-23 */ 103fcf5ef2aSThomas Huth /* FPA registers (ignored). */ 104fcf5ef2aSThomas Huth if (gdb_has_xml) { 105fcf5ef2aSThomas Huth return 0; 106fcf5ef2aSThomas Huth } 107fcf5ef2aSThomas Huth return 12; 108fcf5ef2aSThomas Huth } 109fcf5ef2aSThomas Huth switch (n) { 110fcf5ef2aSThomas Huth case 24: 111fcf5ef2aSThomas Huth /* FPA status register (ignored). */ 112fcf5ef2aSThomas Huth if (gdb_has_xml) { 113fcf5ef2aSThomas Huth return 0; 114fcf5ef2aSThomas Huth } 115fcf5ef2aSThomas Huth return 4; 116fcf5ef2aSThomas Huth case 25: 117c888f7e0SPeter Maydell /* CPSR, or XPSR for M-profile */ 118c888f7e0SPeter Maydell if (arm_feature(env, ARM_FEATURE_M)) { 119c888f7e0SPeter Maydell /* 120c888f7e0SPeter Maydell * Don't allow writing to XPSR.Exception as it can cause 121c888f7e0SPeter Maydell * a transition into or out of handler mode (it's not 1229323e79fSPeter Maydell * writable via the MSR insn so this is a reasonable 123c888f7e0SPeter Maydell * restriction). Other fields are safe to update. 124c888f7e0SPeter Maydell */ 125c888f7e0SPeter Maydell xpsr_write(env, tmp, ~XPSR_EXCP); 126c888f7e0SPeter Maydell } else { 127fcf5ef2aSThomas Huth cpsr_write(env, tmp, 0xffffffff, CPSRWriteByGDBStub); 128c888f7e0SPeter Maydell } 129fcf5ef2aSThomas Huth return 4; 130fcf5ef2aSThomas Huth } 131fcf5ef2aSThomas Huth /* Unknown register. */ 132fcf5ef2aSThomas Huth return 0; 133fcf5ef2aSThomas Huth } 134200bf5b7SAbdallah Bouassida 13589f4f20eSPeter Maydell static int vfp_gdb_get_reg(CPUARMState *env, GByteArray *buf, int reg) 13689f4f20eSPeter Maydell { 13789f4f20eSPeter Maydell ARMCPU *cpu = env_archcpu(env); 13889f4f20eSPeter Maydell int nregs = cpu_isar_feature(aa32_simd_r32, cpu) ? 32 : 16; 13989f4f20eSPeter Maydell 14089f4f20eSPeter Maydell /* VFP data registers are always little-endian. */ 14189f4f20eSPeter Maydell if (reg < nregs) { 14289f4f20eSPeter Maydell return gdb_get_reg64(buf, *aa32_vfp_dreg(env, reg)); 14389f4f20eSPeter Maydell } 14489f4f20eSPeter Maydell if (arm_feature(env, ARM_FEATURE_NEON)) { 14589f4f20eSPeter Maydell /* Aliases for Q regs. */ 14689f4f20eSPeter Maydell nregs += 16; 14789f4f20eSPeter Maydell if (reg < nregs) { 14889f4f20eSPeter Maydell uint64_t *q = aa32_vfp_qreg(env, reg - 32); 14989f4f20eSPeter Maydell return gdb_get_reg128(buf, q[0], q[1]); 15089f4f20eSPeter Maydell } 15189f4f20eSPeter Maydell } 15289f4f20eSPeter Maydell switch (reg - nregs) { 15389f4f20eSPeter Maydell case 0: 15489f4f20eSPeter Maydell return gdb_get_reg32(buf, vfp_get_fpscr(env)); 15589f4f20eSPeter Maydell } 15689f4f20eSPeter Maydell return 0; 15789f4f20eSPeter Maydell } 15889f4f20eSPeter Maydell 15989f4f20eSPeter Maydell static int vfp_gdb_set_reg(CPUARMState *env, uint8_t *buf, int reg) 16089f4f20eSPeter Maydell { 16189f4f20eSPeter Maydell ARMCPU *cpu = env_archcpu(env); 16289f4f20eSPeter Maydell int nregs = cpu_isar_feature(aa32_simd_r32, cpu) ? 32 : 16; 16389f4f20eSPeter Maydell 16489f4f20eSPeter Maydell if (reg < nregs) { 16589f4f20eSPeter Maydell *aa32_vfp_dreg(env, reg) = ldq_le_p(buf); 16689f4f20eSPeter Maydell return 8; 16789f4f20eSPeter Maydell } 16889f4f20eSPeter Maydell if (arm_feature(env, ARM_FEATURE_NEON)) { 16989f4f20eSPeter Maydell nregs += 16; 17089f4f20eSPeter Maydell if (reg < nregs) { 17189f4f20eSPeter Maydell uint64_t *q = aa32_vfp_qreg(env, reg - 32); 17289f4f20eSPeter Maydell q[0] = ldq_le_p(buf); 17389f4f20eSPeter Maydell q[1] = ldq_le_p(buf + 8); 17489f4f20eSPeter Maydell return 16; 17589f4f20eSPeter Maydell } 17689f4f20eSPeter Maydell } 17789f4f20eSPeter Maydell switch (reg - nregs) { 17889f4f20eSPeter Maydell case 0: 179b355f08aSPeter Maydell vfp_set_fpscr(env, ldl_p(buf)); 180b355f08aSPeter Maydell return 4; 181b355f08aSPeter Maydell } 182b355f08aSPeter Maydell return 0; 183b355f08aSPeter Maydell } 184b355f08aSPeter Maydell 185b355f08aSPeter Maydell static int vfp_gdb_get_sysreg(CPUARMState *env, GByteArray *buf, int reg) 186b355f08aSPeter Maydell { 187b355f08aSPeter Maydell switch (reg) { 188b355f08aSPeter Maydell case 0: 189b355f08aSPeter Maydell return gdb_get_reg32(buf, env->vfp.xregs[ARM_VFP_FPSID]); 190b355f08aSPeter Maydell case 1: 191b355f08aSPeter Maydell return gdb_get_reg32(buf, env->vfp.xregs[ARM_VFP_FPEXC]); 192b355f08aSPeter Maydell } 193b355f08aSPeter Maydell return 0; 194b355f08aSPeter Maydell } 195b355f08aSPeter Maydell 196b355f08aSPeter Maydell static int vfp_gdb_set_sysreg(CPUARMState *env, uint8_t *buf, int reg) 197b355f08aSPeter Maydell { 198b355f08aSPeter Maydell switch (reg) { 199b355f08aSPeter Maydell case 0: 20089f4f20eSPeter Maydell env->vfp.xregs[ARM_VFP_FPSID] = ldl_p(buf); 20189f4f20eSPeter Maydell return 4; 20289f4f20eSPeter Maydell case 1: 20389f4f20eSPeter Maydell env->vfp.xregs[ARM_VFP_FPEXC] = ldl_p(buf) & (1 << 30); 20489f4f20eSPeter Maydell return 4; 20589f4f20eSPeter Maydell } 20689f4f20eSPeter Maydell return 0; 20789f4f20eSPeter Maydell } 20889f4f20eSPeter Maydell 209dbd9e084SPeter Maydell static int mve_gdb_get_reg(CPUARMState *env, GByteArray *buf, int reg) 210dbd9e084SPeter Maydell { 211dbd9e084SPeter Maydell switch (reg) { 212dbd9e084SPeter Maydell case 0: 213dbd9e084SPeter Maydell return gdb_get_reg32(buf, env->v7m.vpr); 214dbd9e084SPeter Maydell default: 215dbd9e084SPeter Maydell return 0; 216dbd9e084SPeter Maydell } 217dbd9e084SPeter Maydell } 218dbd9e084SPeter Maydell 219dbd9e084SPeter Maydell static int mve_gdb_set_reg(CPUARMState *env, uint8_t *buf, int reg) 220dbd9e084SPeter Maydell { 221dbd9e084SPeter Maydell switch (reg) { 222dbd9e084SPeter Maydell case 0: 223dbd9e084SPeter Maydell env->v7m.vpr = ldl_p(buf); 224dbd9e084SPeter Maydell return 4; 225dbd9e084SPeter Maydell default: 226dbd9e084SPeter Maydell return 0; 227dbd9e084SPeter Maydell } 228dbd9e084SPeter Maydell } 229dbd9e084SPeter Maydell 23089f4f20eSPeter Maydell /** 23189f4f20eSPeter Maydell * arm_get/set_gdb_*: get/set a gdb register 23289f4f20eSPeter Maydell * @env: the CPU state 23389f4f20eSPeter Maydell * @buf: a buffer to copy to/from 23489f4f20eSPeter Maydell * @reg: register number (offset from start of group) 23589f4f20eSPeter Maydell * 23689f4f20eSPeter Maydell * We return the number of bytes copied 23789f4f20eSPeter Maydell */ 23889f4f20eSPeter Maydell 23989f4f20eSPeter Maydell static int arm_gdb_get_sysreg(CPUARMState *env, GByteArray *buf, int reg) 24089f4f20eSPeter Maydell { 24189f4f20eSPeter Maydell ARMCPU *cpu = env_archcpu(env); 24289f4f20eSPeter Maydell const ARMCPRegInfo *ri; 24389f4f20eSPeter Maydell uint32_t key; 24489f4f20eSPeter Maydell 24589f4f20eSPeter Maydell key = cpu->dyn_sysreg_xml.data.cpregs.keys[reg]; 24689f4f20eSPeter Maydell ri = get_arm_cp_reginfo(cpu->cp_regs, key); 24789f4f20eSPeter Maydell if (ri) { 24889f4f20eSPeter Maydell if (cpreg_field_is_64bit(ri)) { 24989f4f20eSPeter Maydell return gdb_get_reg64(buf, (uint64_t)read_raw_cp_reg(env, ri)); 25089f4f20eSPeter Maydell } else { 25189f4f20eSPeter Maydell return gdb_get_reg32(buf, (uint32_t)read_raw_cp_reg(env, ri)); 25289f4f20eSPeter Maydell } 25389f4f20eSPeter Maydell } 25489f4f20eSPeter Maydell return 0; 25589f4f20eSPeter Maydell } 25689f4f20eSPeter Maydell 25789f4f20eSPeter Maydell static int arm_gdb_set_sysreg(CPUARMState *env, uint8_t *buf, int reg) 25889f4f20eSPeter Maydell { 25989f4f20eSPeter Maydell return 0; 26089f4f20eSPeter Maydell } 26189f4f20eSPeter Maydell 262448d4d14SAlex Bennée static void arm_gen_one_xml_sysreg_tag(GString *s, DynamicGDBXMLInfo *dyn_xml, 263200bf5b7SAbdallah Bouassida ARMCPRegInfo *ri, uint32_t ri_key, 26432d6e32aSAlex Bennée int bitsize, int regnum) 265200bf5b7SAbdallah Bouassida { 266200bf5b7SAbdallah Bouassida g_string_append_printf(s, "<reg name=\"%s\"", ri->name); 267200bf5b7SAbdallah Bouassida g_string_append_printf(s, " bitsize=\"%d\"", bitsize); 26832d6e32aSAlex Bennée g_string_append_printf(s, " regnum=\"%d\"", regnum); 269200bf5b7SAbdallah Bouassida g_string_append_printf(s, " group=\"cp_regs\"/>"); 270448d4d14SAlex Bennée dyn_xml->data.cpregs.keys[dyn_xml->num] = ri_key; 271448d4d14SAlex Bennée dyn_xml->num++; 272200bf5b7SAbdallah Bouassida } 273200bf5b7SAbdallah Bouassida 274200bf5b7SAbdallah Bouassida static void arm_register_sysreg_for_xml(gpointer key, gpointer value, 275200bf5b7SAbdallah Bouassida gpointer p) 276200bf5b7SAbdallah Bouassida { 2775860362dSRichard Henderson uint32_t ri_key = (uintptr_t)key; 278200bf5b7SAbdallah Bouassida ARMCPRegInfo *ri = value; 279200bf5b7SAbdallah Bouassida RegisterSysregXmlParam *param = (RegisterSysregXmlParam *)p; 280200bf5b7SAbdallah Bouassida GString *s = param->s; 281200bf5b7SAbdallah Bouassida ARMCPU *cpu = ARM_CPU(param->cs); 282200bf5b7SAbdallah Bouassida CPUARMState *env = &cpu->env; 283448d4d14SAlex Bennée DynamicGDBXMLInfo *dyn_xml = &cpu->dyn_sysreg_xml; 284200bf5b7SAbdallah Bouassida 285200bf5b7SAbdallah Bouassida if (!(ri->type & (ARM_CP_NO_RAW | ARM_CP_NO_GDB))) { 286200bf5b7SAbdallah Bouassida if (arm_feature(env, ARM_FEATURE_AARCH64)) { 287200bf5b7SAbdallah Bouassida if (ri->state == ARM_CP_STATE_AA64) { 28832d6e32aSAlex Bennée arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 64, 28932d6e32aSAlex Bennée param->n++); 290200bf5b7SAbdallah Bouassida } 291200bf5b7SAbdallah Bouassida } else { 292200bf5b7SAbdallah Bouassida if (ri->state == ARM_CP_STATE_AA32) { 293200bf5b7SAbdallah Bouassida if (!arm_feature(env, ARM_FEATURE_EL3) && 294200bf5b7SAbdallah Bouassida (ri->secure & ARM_CP_SECSTATE_S)) { 295200bf5b7SAbdallah Bouassida return; 296200bf5b7SAbdallah Bouassida } 297200bf5b7SAbdallah Bouassida if (ri->type & ARM_CP_64BIT) { 29832d6e32aSAlex Bennée arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 64, 29932d6e32aSAlex Bennée param->n++); 300200bf5b7SAbdallah Bouassida } else { 30132d6e32aSAlex Bennée arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 32, 30232d6e32aSAlex Bennée param->n++); 303200bf5b7SAbdallah Bouassida } 304200bf5b7SAbdallah Bouassida } 305200bf5b7SAbdallah Bouassida } 306200bf5b7SAbdallah Bouassida } 307200bf5b7SAbdallah Bouassida } 308200bf5b7SAbdallah Bouassida 3094bce95b4SRichard Henderson static int arm_gen_dynamic_sysreg_xml(CPUState *cs, int base_reg) 310200bf5b7SAbdallah Bouassida { 311200bf5b7SAbdallah Bouassida ARMCPU *cpu = ARM_CPU(cs); 312200bf5b7SAbdallah Bouassida GString *s = g_string_new(NULL); 31332d6e32aSAlex Bennée RegisterSysregXmlParam param = {cs, s, base_reg}; 314200bf5b7SAbdallah Bouassida 315448d4d14SAlex Bennée cpu->dyn_sysreg_xml.num = 0; 316448d4d14SAlex Bennée cpu->dyn_sysreg_xml.data.cpregs.keys = g_new(uint32_t, g_hash_table_size(cpu->cp_regs)); 317200bf5b7SAbdallah Bouassida g_string_printf(s, "<?xml version=\"1.0\"?>"); 318200bf5b7SAbdallah Bouassida g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">"); 319200bf5b7SAbdallah Bouassida g_string_append_printf(s, "<feature name=\"org.qemu.gdb.arm.sys.regs\">"); 320200bf5b7SAbdallah Bouassida g_hash_table_foreach(cpu->cp_regs, arm_register_sysreg_for_xml, ¶m); 321200bf5b7SAbdallah Bouassida g_string_append_printf(s, "</feature>"); 322448d4d14SAlex Bennée cpu->dyn_sysreg_xml.desc = g_string_free(s, false); 323448d4d14SAlex Bennée return cpu->dyn_sysreg_xml.num; 324200bf5b7SAbdallah Bouassida } 325200bf5b7SAbdallah Bouassida 3267d8b28b8SRichard Henderson typedef enum { 3277d8b28b8SRichard Henderson M_SYSREG_MSP, 3287d8b28b8SRichard Henderson M_SYSREG_PSP, 3297d8b28b8SRichard Henderson M_SYSREG_PRIMASK, 3307d8b28b8SRichard Henderson M_SYSREG_CONTROL, 3317d8b28b8SRichard Henderson M_SYSREG_BASEPRI, 3327d8b28b8SRichard Henderson M_SYSREG_FAULTMASK, 3337d8b28b8SRichard Henderson M_SYSREG_MSPLIM, 3347d8b28b8SRichard Henderson M_SYSREG_PSPLIM, 3357d8b28b8SRichard Henderson } MProfileSysreg; 3367d8b28b8SRichard Henderson 3377d8b28b8SRichard Henderson static const struct { 3387d8b28b8SRichard Henderson const char *name; 3397d8b28b8SRichard Henderson int feature; 3407d8b28b8SRichard Henderson } m_sysreg_def[] = { 3417d8b28b8SRichard Henderson [M_SYSREG_MSP] = { "msp", ARM_FEATURE_M }, 3427d8b28b8SRichard Henderson [M_SYSREG_PSP] = { "psp", ARM_FEATURE_M }, 3437d8b28b8SRichard Henderson [M_SYSREG_PRIMASK] = { "primask", ARM_FEATURE_M }, 3447d8b28b8SRichard Henderson [M_SYSREG_CONTROL] = { "control", ARM_FEATURE_M }, 3457d8b28b8SRichard Henderson [M_SYSREG_BASEPRI] = { "basepri", ARM_FEATURE_M_MAIN }, 3467d8b28b8SRichard Henderson [M_SYSREG_FAULTMASK] = { "faultmask", ARM_FEATURE_M_MAIN }, 3477d8b28b8SRichard Henderson [M_SYSREG_MSPLIM] = { "msplim", ARM_FEATURE_V8 }, 3487d8b28b8SRichard Henderson [M_SYSREG_PSPLIM] = { "psplim", ARM_FEATURE_V8 }, 3497d8b28b8SRichard Henderson }; 3507d8b28b8SRichard Henderson 3517d8b28b8SRichard Henderson static uint32_t *m_sysreg_ptr(CPUARMState *env, MProfileSysreg reg, bool sec) 3527d8b28b8SRichard Henderson { 3537d8b28b8SRichard Henderson uint32_t *ptr; 3547d8b28b8SRichard Henderson 3557d8b28b8SRichard Henderson switch (reg) { 3567d8b28b8SRichard Henderson case M_SYSREG_MSP: 3577d8b28b8SRichard Henderson ptr = arm_v7m_get_sp_ptr(env, sec, false, true); 3587d8b28b8SRichard Henderson break; 3597d8b28b8SRichard Henderson case M_SYSREG_PSP: 3607d8b28b8SRichard Henderson ptr = arm_v7m_get_sp_ptr(env, sec, true, true); 3617d8b28b8SRichard Henderson break; 3627d8b28b8SRichard Henderson case M_SYSREG_MSPLIM: 3637d8b28b8SRichard Henderson ptr = &env->v7m.msplim[sec]; 3647d8b28b8SRichard Henderson break; 3657d8b28b8SRichard Henderson case M_SYSREG_PSPLIM: 3667d8b28b8SRichard Henderson ptr = &env->v7m.psplim[sec]; 3677d8b28b8SRichard Henderson break; 3687d8b28b8SRichard Henderson case M_SYSREG_PRIMASK: 3697d8b28b8SRichard Henderson ptr = &env->v7m.primask[sec]; 3707d8b28b8SRichard Henderson break; 3717d8b28b8SRichard Henderson case M_SYSREG_BASEPRI: 3727d8b28b8SRichard Henderson ptr = &env->v7m.basepri[sec]; 3737d8b28b8SRichard Henderson break; 3747d8b28b8SRichard Henderson case M_SYSREG_FAULTMASK: 3757d8b28b8SRichard Henderson ptr = &env->v7m.faultmask[sec]; 3767d8b28b8SRichard Henderson break; 3777d8b28b8SRichard Henderson case M_SYSREG_CONTROL: 3787d8b28b8SRichard Henderson ptr = &env->v7m.control[sec]; 3797d8b28b8SRichard Henderson break; 3807d8b28b8SRichard Henderson default: 3817d8b28b8SRichard Henderson return NULL; 3827d8b28b8SRichard Henderson } 3837d8b28b8SRichard Henderson return arm_feature(env, m_sysreg_def[reg].feature) ? ptr : NULL; 3847d8b28b8SRichard Henderson } 3857d8b28b8SRichard Henderson 3867d8b28b8SRichard Henderson static int m_sysreg_get(CPUARMState *env, GByteArray *buf, 3877d8b28b8SRichard Henderson MProfileSysreg reg, bool secure) 3887d8b28b8SRichard Henderson { 3897d8b28b8SRichard Henderson uint32_t *ptr = m_sysreg_ptr(env, reg, secure); 3907d8b28b8SRichard Henderson 3917d8b28b8SRichard Henderson if (ptr == NULL) { 3927d8b28b8SRichard Henderson return 0; 3937d8b28b8SRichard Henderson } 3947d8b28b8SRichard Henderson return gdb_get_reg32(buf, *ptr); 3957d8b28b8SRichard Henderson } 3967d8b28b8SRichard Henderson 3977d8b28b8SRichard Henderson static int arm_gdb_get_m_systemreg(CPUARMState *env, GByteArray *buf, int reg) 3987d8b28b8SRichard Henderson { 3997d8b28b8SRichard Henderson /* 4007d8b28b8SRichard Henderson * Here, we emulate MRS instruction, where CONTROL has a mix of 4017d8b28b8SRichard Henderson * banked and non-banked bits. 4027d8b28b8SRichard Henderson */ 4037d8b28b8SRichard Henderson if (reg == M_SYSREG_CONTROL) { 4047d8b28b8SRichard Henderson return gdb_get_reg32(buf, arm_v7m_mrs_control(env, env->v7m.secure)); 4057d8b28b8SRichard Henderson } 4067d8b28b8SRichard Henderson return m_sysreg_get(env, buf, reg, env->v7m.secure); 4077d8b28b8SRichard Henderson } 4087d8b28b8SRichard Henderson 4097d8b28b8SRichard Henderson static int arm_gdb_set_m_systemreg(CPUARMState *env, uint8_t *buf, int reg) 4107d8b28b8SRichard Henderson { 4117d8b28b8SRichard Henderson return 0; /* TODO */ 4127d8b28b8SRichard Henderson } 4137d8b28b8SRichard Henderson 4147d8b28b8SRichard Henderson static int arm_gen_dynamic_m_systemreg_xml(CPUState *cs, int orig_base_reg) 4157d8b28b8SRichard Henderson { 4167d8b28b8SRichard Henderson ARMCPU *cpu = ARM_CPU(cs); 4177d8b28b8SRichard Henderson CPUARMState *env = &cpu->env; 4187d8b28b8SRichard Henderson GString *s = g_string_new(NULL); 4197d8b28b8SRichard Henderson int base_reg = orig_base_reg; 4207d8b28b8SRichard Henderson int i; 4217d8b28b8SRichard Henderson 4227d8b28b8SRichard Henderson g_string_printf(s, "<?xml version=\"1.0\"?>"); 4237d8b28b8SRichard Henderson g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">"); 4247d8b28b8SRichard Henderson g_string_append_printf(s, "<feature name=\"org.gnu.gdb.arm.m-system\">\n"); 4257d8b28b8SRichard Henderson 4267d8b28b8SRichard Henderson for (i = 0; i < ARRAY_SIZE(m_sysreg_def); i++) { 4277d8b28b8SRichard Henderson if (arm_feature(env, m_sysreg_def[i].feature)) { 4287d8b28b8SRichard Henderson g_string_append_printf(s, 4297d8b28b8SRichard Henderson "<reg name=\"%s\" bitsize=\"32\" regnum=\"%d\"/>\n", 4307d8b28b8SRichard Henderson m_sysreg_def[i].name, base_reg++); 4317d8b28b8SRichard Henderson } 4327d8b28b8SRichard Henderson } 4337d8b28b8SRichard Henderson 4347d8b28b8SRichard Henderson g_string_append_printf(s, "</feature>"); 4357d8b28b8SRichard Henderson cpu->dyn_m_systemreg_xml.desc = g_string_free(s, false); 4367d8b28b8SRichard Henderson cpu->dyn_m_systemreg_xml.num = base_reg - orig_base_reg; 4377d8b28b8SRichard Henderson 4387d8b28b8SRichard Henderson return cpu->dyn_m_systemreg_xml.num; 4397d8b28b8SRichard Henderson } 4407d8b28b8SRichard Henderson 4417d8b28b8SRichard Henderson #ifndef CONFIG_USER_ONLY 4427d8b28b8SRichard Henderson /* 4437d8b28b8SRichard Henderson * For user-only, we see the non-secure registers via m_systemreg above. 4447d8b28b8SRichard Henderson * For secext, encode the non-secure view as even and secure view as odd. 4457d8b28b8SRichard Henderson */ 4467d8b28b8SRichard Henderson static int arm_gdb_get_m_secextreg(CPUARMState *env, GByteArray *buf, int reg) 4477d8b28b8SRichard Henderson { 4487d8b28b8SRichard Henderson return m_sysreg_get(env, buf, reg >> 1, reg & 1); 4497d8b28b8SRichard Henderson } 4507d8b28b8SRichard Henderson 4517d8b28b8SRichard Henderson static int arm_gdb_set_m_secextreg(CPUARMState *env, uint8_t *buf, int reg) 4527d8b28b8SRichard Henderson { 4537d8b28b8SRichard Henderson return 0; /* TODO */ 4547d8b28b8SRichard Henderson } 4557d8b28b8SRichard Henderson 4567d8b28b8SRichard Henderson static int arm_gen_dynamic_m_secextreg_xml(CPUState *cs, int orig_base_reg) 4577d8b28b8SRichard Henderson { 4587d8b28b8SRichard Henderson ARMCPU *cpu = ARM_CPU(cs); 4597d8b28b8SRichard Henderson GString *s = g_string_new(NULL); 4607d8b28b8SRichard Henderson int base_reg = orig_base_reg; 4617d8b28b8SRichard Henderson int i; 4627d8b28b8SRichard Henderson 4637d8b28b8SRichard Henderson g_string_printf(s, "<?xml version=\"1.0\"?>"); 4647d8b28b8SRichard Henderson g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">"); 4657d8b28b8SRichard Henderson g_string_append_printf(s, "<feature name=\"org.gnu.gdb.arm.secext\">\n"); 4667d8b28b8SRichard Henderson 4677d8b28b8SRichard Henderson for (i = 0; i < ARRAY_SIZE(m_sysreg_def); i++) { 4687d8b28b8SRichard Henderson g_string_append_printf(s, 4697d8b28b8SRichard Henderson "<reg name=\"%s_ns\" bitsize=\"32\" regnum=\"%d\"/>\n", 4707d8b28b8SRichard Henderson m_sysreg_def[i].name, base_reg++); 4717d8b28b8SRichard Henderson g_string_append_printf(s, 4727d8b28b8SRichard Henderson "<reg name=\"%s_s\" bitsize=\"32\" regnum=\"%d\"/>\n", 4737d8b28b8SRichard Henderson m_sysreg_def[i].name, base_reg++); 4747d8b28b8SRichard Henderson } 4757d8b28b8SRichard Henderson 4767d8b28b8SRichard Henderson g_string_append_printf(s, "</feature>"); 4777d8b28b8SRichard Henderson cpu->dyn_m_secextreg_xml.desc = g_string_free(s, false); 4787d8b28b8SRichard Henderson cpu->dyn_m_secextreg_xml.num = base_reg - orig_base_reg; 4797d8b28b8SRichard Henderson 4807d8b28b8SRichard Henderson return cpu->dyn_m_secextreg_xml.num; 4817d8b28b8SRichard Henderson } 4827d8b28b8SRichard Henderson #endif 4837d8b28b8SRichard Henderson 484200bf5b7SAbdallah Bouassida const char *arm_gdb_get_dynamic_xml(CPUState *cs, const char *xmlname) 485200bf5b7SAbdallah Bouassida { 486200bf5b7SAbdallah Bouassida ARMCPU *cpu = ARM_CPU(cs); 487200bf5b7SAbdallah Bouassida 488200bf5b7SAbdallah Bouassida if (strcmp(xmlname, "system-registers.xml") == 0) { 489448d4d14SAlex Bennée return cpu->dyn_sysreg_xml.desc; 490d12379c5SAlex Bennée } else if (strcmp(xmlname, "sve-registers.xml") == 0) { 491d12379c5SAlex Bennée return cpu->dyn_svereg_xml.desc; 4927d8b28b8SRichard Henderson } else if (strcmp(xmlname, "arm-m-system.xml") == 0) { 4937d8b28b8SRichard Henderson return cpu->dyn_m_systemreg_xml.desc; 4947d8b28b8SRichard Henderson #ifndef CONFIG_USER_ONLY 4957d8b28b8SRichard Henderson } else if (strcmp(xmlname, "arm-m-secext.xml") == 0) { 4967d8b28b8SRichard Henderson return cpu->dyn_m_secextreg_xml.desc; 4977d8b28b8SRichard Henderson #endif 498200bf5b7SAbdallah Bouassida } 499200bf5b7SAbdallah Bouassida return NULL; 500200bf5b7SAbdallah Bouassida } 50189f4f20eSPeter Maydell 50289f4f20eSPeter Maydell void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu) 50389f4f20eSPeter Maydell { 50489f4f20eSPeter Maydell CPUState *cs = CPU(cpu); 50589f4f20eSPeter Maydell CPUARMState *env = &cpu->env; 50689f4f20eSPeter Maydell 50789f4f20eSPeter Maydell if (arm_feature(env, ARM_FEATURE_AARCH64)) { 50889f4f20eSPeter Maydell /* 50989f4f20eSPeter Maydell * The lower part of each SVE register aliases to the FPU 51089f4f20eSPeter Maydell * registers so we don't need to include both. 51189f4f20eSPeter Maydell */ 51289f4f20eSPeter Maydell #ifdef TARGET_AARCH64 51389f4f20eSPeter Maydell if (isar_feature_aa64_sve(&cpu->isar)) { 514963a6b91SRichard Henderson int nreg = arm_gen_dynamic_svereg_xml(cs, cs->gdb_num_regs); 515963a6b91SRichard Henderson gdb_register_coprocessor(cs, aarch64_gdb_get_sve_reg, 516963a6b91SRichard Henderson aarch64_gdb_set_sve_reg, nreg, 51789f4f20eSPeter Maydell "sve-registers.xml", 0); 51889f4f20eSPeter Maydell } else { 519963a6b91SRichard Henderson gdb_register_coprocessor(cs, aarch64_gdb_get_fpu_reg, 520963a6b91SRichard Henderson aarch64_gdb_set_fpu_reg, 52189f4f20eSPeter Maydell 34, "aarch64-fpu.xml", 0); 52289f4f20eSPeter Maydell } 523*5787d17aSPeter Maydell #if 0 524*5787d17aSPeter Maydell /* 525*5787d17aSPeter Maydell * GDB versions 9 through 12 have a bug which means they will 526*5787d17aSPeter Maydell * crash if they see this XML from QEMU; disable it for the 8.0 527*5787d17aSPeter Maydell * release, pending a better solution. 528*5787d17aSPeter Maydell */ 529e995d5ccSRichard Henderson if (isar_feature_aa64_pauth(&cpu->isar)) { 530e995d5ccSRichard Henderson gdb_register_coprocessor(cs, aarch64_gdb_get_pauth_reg, 531e995d5ccSRichard Henderson aarch64_gdb_set_pauth_reg, 532e995d5ccSRichard Henderson 4, "aarch64-pauth.xml", 0); 533e995d5ccSRichard Henderson } 53489f4f20eSPeter Maydell #endif 535*5787d17aSPeter Maydell #endif 536b355f08aSPeter Maydell } else { 537b355f08aSPeter Maydell if (arm_feature(env, ARM_FEATURE_NEON)) { 53889f4f20eSPeter Maydell gdb_register_coprocessor(cs, vfp_gdb_get_reg, vfp_gdb_set_reg, 539b355f08aSPeter Maydell 49, "arm-neon.xml", 0); 54089f4f20eSPeter Maydell } else if (cpu_isar_feature(aa32_simd_r32, cpu)) { 54189f4f20eSPeter Maydell gdb_register_coprocessor(cs, vfp_gdb_get_reg, vfp_gdb_set_reg, 542b355f08aSPeter Maydell 33, "arm-vfp3.xml", 0); 54389f4f20eSPeter Maydell } else if (cpu_isar_feature(aa32_vfp_simd, cpu)) { 54489f4f20eSPeter Maydell gdb_register_coprocessor(cs, vfp_gdb_get_reg, vfp_gdb_set_reg, 545b355f08aSPeter Maydell 17, "arm-vfp.xml", 0); 546b355f08aSPeter Maydell } 547b355f08aSPeter Maydell if (!arm_feature(env, ARM_FEATURE_M)) { 548b355f08aSPeter Maydell /* 549b355f08aSPeter Maydell * A and R profile have FP sysregs FPEXC and FPSID that we 550b355f08aSPeter Maydell * expose to gdb. 551b355f08aSPeter Maydell */ 552b355f08aSPeter Maydell gdb_register_coprocessor(cs, vfp_gdb_get_sysreg, vfp_gdb_set_sysreg, 553b355f08aSPeter Maydell 2, "arm-vfp-sysregs.xml", 0); 554b355f08aSPeter Maydell } 55589f4f20eSPeter Maydell } 556dbd9e084SPeter Maydell if (cpu_isar_feature(aa32_mve, cpu)) { 557dbd9e084SPeter Maydell gdb_register_coprocessor(cs, mve_gdb_get_reg, mve_gdb_set_reg, 558dbd9e084SPeter Maydell 1, "arm-m-profile-mve.xml", 0); 559dbd9e084SPeter Maydell } 56089f4f20eSPeter Maydell gdb_register_coprocessor(cs, arm_gdb_get_sysreg, arm_gdb_set_sysreg, 56189f4f20eSPeter Maydell arm_gen_dynamic_sysreg_xml(cs, cs->gdb_num_regs), 56289f4f20eSPeter Maydell "system-registers.xml", 0); 56389f4f20eSPeter Maydell 5647d8b28b8SRichard Henderson if (arm_feature(env, ARM_FEATURE_M)) { 5657d8b28b8SRichard Henderson gdb_register_coprocessor(cs, 5667d8b28b8SRichard Henderson arm_gdb_get_m_systemreg, arm_gdb_set_m_systemreg, 5677d8b28b8SRichard Henderson arm_gen_dynamic_m_systemreg_xml(cs, cs->gdb_num_regs), 5687d8b28b8SRichard Henderson "arm-m-system.xml", 0); 5697d8b28b8SRichard Henderson #ifndef CONFIG_USER_ONLY 5707d8b28b8SRichard Henderson if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { 5717d8b28b8SRichard Henderson gdb_register_coprocessor(cs, 5727d8b28b8SRichard Henderson arm_gdb_get_m_secextreg, arm_gdb_set_m_secextreg, 5737d8b28b8SRichard Henderson arm_gen_dynamic_m_secextreg_xml(cs, cs->gdb_num_regs), 5747d8b28b8SRichard Henderson "arm-m-secext.xml", 0); 5757d8b28b8SRichard Henderson } 5767d8b28b8SRichard Henderson #endif 5777d8b28b8SRichard Henderson } 57889f4f20eSPeter Maydell } 579