1fcf5ef2aSThomas Huth /*
2fcf5ef2aSThomas Huth * ARM gdb server stub: AArch64 specific functions.
3fcf5ef2aSThomas Huth *
4fcf5ef2aSThomas Huth * Copyright (c) 2013 SUSE LINUX Products GmbH
5fcf5ef2aSThomas Huth *
6fcf5ef2aSThomas Huth * This library is free software; you can redistribute it and/or
7fcf5ef2aSThomas Huth * modify it under the terms of the GNU Lesser General Public
8fcf5ef2aSThomas Huth * License as published by the Free Software Foundation; either
950f57e09SChetan Pant * version 2.1 of the License, or (at your option) any later version.
10fcf5ef2aSThomas Huth *
11fcf5ef2aSThomas Huth * This library is distributed in the hope that it will be useful,
12fcf5ef2aSThomas Huth * but WITHOUT ANY WARRANTY; without even the implied warranty of
13fcf5ef2aSThomas Huth * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14fcf5ef2aSThomas Huth * Lesser General Public License for more details.
15fcf5ef2aSThomas Huth *
16fcf5ef2aSThomas Huth * You should have received a copy of the GNU Lesser General Public
17fcf5ef2aSThomas Huth * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18fcf5ef2aSThomas Huth */
19fcf5ef2aSThomas Huth #include "qemu/osdep.h"
2089f4f20eSPeter Maydell #include "qemu/log.h"
21fcf5ef2aSThomas Huth #include "cpu.h"
2289f4f20eSPeter Maydell #include "internals.h"
234ea5fe99SAlex Bennée #include "gdbstub/helpers.h"
24f81198ceSGustavo Romero #include "gdbstub/commands.h"
25f81198ceSGustavo Romero #include "tcg/mte_helper.h"
26f81198ceSGustavo Romero #if defined(CONFIG_USER_ONLY) && defined(CONFIG_LINUX)
27f81198ceSGustavo Romero #include <sys/prctl.h>
28f81198ceSGustavo Romero #include "mte_user_helper.h"
29f81198ceSGustavo Romero #endif
30fcf5ef2aSThomas Huth
aarch64_cpu_gdb_read_register(CPUState * cs,GByteArray * mem_buf,int n)31a010bdbeSAlex Bennée int aarch64_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
32fcf5ef2aSThomas Huth {
33fcf5ef2aSThomas Huth ARMCPU *cpu = ARM_CPU(cs);
34fcf5ef2aSThomas Huth CPUARMState *env = &cpu->env;
35fcf5ef2aSThomas Huth
36fcf5ef2aSThomas Huth if (n < 31) {
37fcf5ef2aSThomas Huth /* Core integer register. */
38fcf5ef2aSThomas Huth return gdb_get_reg64(mem_buf, env->xregs[n]);
39fcf5ef2aSThomas Huth }
40fcf5ef2aSThomas Huth switch (n) {
41fcf5ef2aSThomas Huth case 31:
42fcf5ef2aSThomas Huth return gdb_get_reg64(mem_buf, env->xregs[31]);
43fcf5ef2aSThomas Huth case 32:
44fcf5ef2aSThomas Huth return gdb_get_reg64(mem_buf, env->pc);
45fcf5ef2aSThomas Huth case 33:
46fcf5ef2aSThomas Huth return gdb_get_reg32(mem_buf, pstate_read(env));
47fcf5ef2aSThomas Huth }
48fcf5ef2aSThomas Huth /* Unknown register. */
49fcf5ef2aSThomas Huth return 0;
50fcf5ef2aSThomas Huth }
51fcf5ef2aSThomas Huth
aarch64_cpu_gdb_write_register(CPUState * cs,uint8_t * mem_buf,int n)52fcf5ef2aSThomas Huth int aarch64_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
53fcf5ef2aSThomas Huth {
54fcf5ef2aSThomas Huth ARMCPU *cpu = ARM_CPU(cs);
55fcf5ef2aSThomas Huth CPUARMState *env = &cpu->env;
56fcf5ef2aSThomas Huth uint64_t tmp;
57fcf5ef2aSThomas Huth
58fcf5ef2aSThomas Huth tmp = ldq_p(mem_buf);
59fcf5ef2aSThomas Huth
60fcf5ef2aSThomas Huth if (n < 31) {
61fcf5ef2aSThomas Huth /* Core integer register. */
62fcf5ef2aSThomas Huth env->xregs[n] = tmp;
63fcf5ef2aSThomas Huth return 8;
64fcf5ef2aSThomas Huth }
65fcf5ef2aSThomas Huth switch (n) {
66fcf5ef2aSThomas Huth case 31:
67fcf5ef2aSThomas Huth env->xregs[31] = tmp;
68fcf5ef2aSThomas Huth return 8;
69fcf5ef2aSThomas Huth case 32:
70fcf5ef2aSThomas Huth env->pc = tmp;
71fcf5ef2aSThomas Huth return 8;
72fcf5ef2aSThomas Huth case 33:
73fcf5ef2aSThomas Huth /* CPSR */
74fcf5ef2aSThomas Huth pstate_write(env, tmp);
75fcf5ef2aSThomas Huth return 4;
76fcf5ef2aSThomas Huth }
77fcf5ef2aSThomas Huth /* Unknown register. */
78fcf5ef2aSThomas Huth return 0;
79fcf5ef2aSThomas Huth }
8089f4f20eSPeter Maydell
aarch64_gdb_get_fpu_reg(CPUState * cs,GByteArray * buf,int reg)8166260159SAkihiko Odaki int aarch64_gdb_get_fpu_reg(CPUState *cs, GByteArray *buf, int reg)
8289f4f20eSPeter Maydell {
8366260159SAkihiko Odaki ARMCPU *cpu = ARM_CPU(cs);
8466260159SAkihiko Odaki CPUARMState *env = &cpu->env;
8566260159SAkihiko Odaki
8689f4f20eSPeter Maydell switch (reg) {
8789f4f20eSPeter Maydell case 0 ... 31:
8889f4f20eSPeter Maydell {
8989f4f20eSPeter Maydell /* 128 bit FP register - quads are in LE order */
9089f4f20eSPeter Maydell uint64_t *q = aa64_vfp_qreg(env, reg);
9189f4f20eSPeter Maydell return gdb_get_reg128(buf, q[1], q[0]);
9289f4f20eSPeter Maydell }
9389f4f20eSPeter Maydell case 32:
9489f4f20eSPeter Maydell /* FPSR */
9589f4f20eSPeter Maydell return gdb_get_reg32(buf, vfp_get_fpsr(env));
9689f4f20eSPeter Maydell case 33:
9789f4f20eSPeter Maydell /* FPCR */
9889f4f20eSPeter Maydell return gdb_get_reg32(buf, vfp_get_fpcr(env));
9989f4f20eSPeter Maydell default:
10089f4f20eSPeter Maydell return 0;
10189f4f20eSPeter Maydell }
10289f4f20eSPeter Maydell }
10389f4f20eSPeter Maydell
aarch64_gdb_set_fpu_reg(CPUState * cs,uint8_t * buf,int reg)10466260159SAkihiko Odaki int aarch64_gdb_set_fpu_reg(CPUState *cs, uint8_t *buf, int reg)
10589f4f20eSPeter Maydell {
10666260159SAkihiko Odaki ARMCPU *cpu = ARM_CPU(cs);
10766260159SAkihiko Odaki CPUARMState *env = &cpu->env;
10866260159SAkihiko Odaki
10989f4f20eSPeter Maydell switch (reg) {
11089f4f20eSPeter Maydell case 0 ... 31:
11189f4f20eSPeter Maydell /* 128 bit FP register */
11289f4f20eSPeter Maydell {
11389f4f20eSPeter Maydell uint64_t *q = aa64_vfp_qreg(env, reg);
11489f4f20eSPeter Maydell q[0] = ldq_le_p(buf);
11589f4f20eSPeter Maydell q[1] = ldq_le_p(buf + 8);
11689f4f20eSPeter Maydell return 16;
11789f4f20eSPeter Maydell }
11889f4f20eSPeter Maydell case 32:
11989f4f20eSPeter Maydell /* FPSR */
12089f4f20eSPeter Maydell vfp_set_fpsr(env, ldl_p(buf));
12189f4f20eSPeter Maydell return 4;
12289f4f20eSPeter Maydell case 33:
12389f4f20eSPeter Maydell /* FPCR */
12489f4f20eSPeter Maydell vfp_set_fpcr(env, ldl_p(buf));
12589f4f20eSPeter Maydell return 4;
12689f4f20eSPeter Maydell default:
12789f4f20eSPeter Maydell return 0;
12889f4f20eSPeter Maydell }
12989f4f20eSPeter Maydell }
13089f4f20eSPeter Maydell
aarch64_gdb_get_sve_reg(CPUState * cs,GByteArray * buf,int reg)13166260159SAkihiko Odaki int aarch64_gdb_get_sve_reg(CPUState *cs, GByteArray *buf, int reg)
13289f4f20eSPeter Maydell {
13366260159SAkihiko Odaki ARMCPU *cpu = ARM_CPU(cs);
13466260159SAkihiko Odaki CPUARMState *env = &cpu->env;
13589f4f20eSPeter Maydell
13689f4f20eSPeter Maydell switch (reg) {
13789f4f20eSPeter Maydell /* The first 32 registers are the zregs */
13889f4f20eSPeter Maydell case 0 ... 31:
13989f4f20eSPeter Maydell {
14089f4f20eSPeter Maydell int vq, len = 0;
14189f4f20eSPeter Maydell for (vq = 0; vq < cpu->sve_max_vq; vq++) {
14289f4f20eSPeter Maydell len += gdb_get_reg128(buf,
14389f4f20eSPeter Maydell env->vfp.zregs[reg].d[vq * 2 + 1],
14489f4f20eSPeter Maydell env->vfp.zregs[reg].d[vq * 2]);
14589f4f20eSPeter Maydell }
14689f4f20eSPeter Maydell return len;
14789f4f20eSPeter Maydell }
14889f4f20eSPeter Maydell case 32:
14989f4f20eSPeter Maydell return gdb_get_reg32(buf, vfp_get_fpsr(env));
15089f4f20eSPeter Maydell case 33:
15189f4f20eSPeter Maydell return gdb_get_reg32(buf, vfp_get_fpcr(env));
15289f4f20eSPeter Maydell /* then 16 predicates and the ffr */
15389f4f20eSPeter Maydell case 34 ... 50:
15489f4f20eSPeter Maydell {
15589f4f20eSPeter Maydell int preg = reg - 34;
15689f4f20eSPeter Maydell int vq, len = 0;
15789f4f20eSPeter Maydell for (vq = 0; vq < cpu->sve_max_vq; vq = vq + 4) {
15889f4f20eSPeter Maydell len += gdb_get_reg64(buf, env->vfp.pregs[preg].p[vq / 4]);
15989f4f20eSPeter Maydell }
16089f4f20eSPeter Maydell return len;
16189f4f20eSPeter Maydell }
16289f4f20eSPeter Maydell case 51:
16389f4f20eSPeter Maydell {
16489f4f20eSPeter Maydell /*
16589f4f20eSPeter Maydell * We report in Vector Granules (VG) which is 64bit in a Z reg
16689f4f20eSPeter Maydell * while the ZCR works in Vector Quads (VQ) which is 128bit chunks.
16789f4f20eSPeter Maydell */
1685ef3cc56SRichard Henderson int vq = sve_vqm1_for_el(env, arm_current_el(env)) + 1;
16989f4f20eSPeter Maydell return gdb_get_reg64(buf, vq * 2);
17089f4f20eSPeter Maydell }
17189f4f20eSPeter Maydell default:
17289f4f20eSPeter Maydell /* gdbstub asked for something out our range */
17389f4f20eSPeter Maydell qemu_log_mask(LOG_UNIMP, "%s: out of range register %d", __func__, reg);
17489f4f20eSPeter Maydell break;
17589f4f20eSPeter Maydell }
17689f4f20eSPeter Maydell
17789f4f20eSPeter Maydell return 0;
17889f4f20eSPeter Maydell }
17989f4f20eSPeter Maydell
aarch64_gdb_set_sve_reg(CPUState * cs,uint8_t * buf,int reg)18066260159SAkihiko Odaki int aarch64_gdb_set_sve_reg(CPUState *cs, uint8_t *buf, int reg)
18189f4f20eSPeter Maydell {
18266260159SAkihiko Odaki ARMCPU *cpu = ARM_CPU(cs);
18366260159SAkihiko Odaki CPUARMState *env = &cpu->env;
18489f4f20eSPeter Maydell
18589f4f20eSPeter Maydell /* The first 32 registers are the zregs */
18689f4f20eSPeter Maydell switch (reg) {
18789f4f20eSPeter Maydell /* The first 32 registers are the zregs */
18889f4f20eSPeter Maydell case 0 ... 31:
18989f4f20eSPeter Maydell {
19089f4f20eSPeter Maydell int vq, len = 0;
19189f4f20eSPeter Maydell uint64_t *p = (uint64_t *) buf;
19289f4f20eSPeter Maydell for (vq = 0; vq < cpu->sve_max_vq; vq++) {
19389f4f20eSPeter Maydell env->vfp.zregs[reg].d[vq * 2 + 1] = *p++;
19489f4f20eSPeter Maydell env->vfp.zregs[reg].d[vq * 2] = *p++;
19589f4f20eSPeter Maydell len += 16;
19689f4f20eSPeter Maydell }
19789f4f20eSPeter Maydell return len;
19889f4f20eSPeter Maydell }
19989f4f20eSPeter Maydell case 32:
20089f4f20eSPeter Maydell vfp_set_fpsr(env, *(uint32_t *)buf);
20189f4f20eSPeter Maydell return 4;
20289f4f20eSPeter Maydell case 33:
20389f4f20eSPeter Maydell vfp_set_fpcr(env, *(uint32_t *)buf);
20489f4f20eSPeter Maydell return 4;
20589f4f20eSPeter Maydell case 34 ... 50:
20689f4f20eSPeter Maydell {
20789f4f20eSPeter Maydell int preg = reg - 34;
20889f4f20eSPeter Maydell int vq, len = 0;
20989f4f20eSPeter Maydell uint64_t *p = (uint64_t *) buf;
21089f4f20eSPeter Maydell for (vq = 0; vq < cpu->sve_max_vq; vq = vq + 4) {
21189f4f20eSPeter Maydell env->vfp.pregs[preg].p[vq / 4] = *p++;
21289f4f20eSPeter Maydell len += 8;
21389f4f20eSPeter Maydell }
21489f4f20eSPeter Maydell return len;
21589f4f20eSPeter Maydell }
21689f4f20eSPeter Maydell case 51:
21789f4f20eSPeter Maydell /* cannot set vg via gdbstub */
21889f4f20eSPeter Maydell return 0;
21989f4f20eSPeter Maydell default:
22089f4f20eSPeter Maydell /* gdbstub asked for something out our range */
22189f4f20eSPeter Maydell break;
22289f4f20eSPeter Maydell }
22389f4f20eSPeter Maydell
22489f4f20eSPeter Maydell return 0;
22589f4f20eSPeter Maydell }
226e03aba88SRichard Henderson
aarch64_gdb_get_pauth_reg(CPUState * cs,GByteArray * buf,int reg)22766260159SAkihiko Odaki int aarch64_gdb_get_pauth_reg(CPUState *cs, GByteArray *buf, int reg)
228e995d5ccSRichard Henderson {
22966260159SAkihiko Odaki ARMCPU *cpu = ARM_CPU(cs);
23066260159SAkihiko Odaki CPUARMState *env = &cpu->env;
23166260159SAkihiko Odaki
232e995d5ccSRichard Henderson switch (reg) {
233e995d5ccSRichard Henderson case 0: /* pauth_dmask */
234e995d5ccSRichard Henderson case 1: /* pauth_cmask */
235e995d5ccSRichard Henderson case 2: /* pauth_dmask_high */
236e995d5ccSRichard Henderson case 3: /* pauth_cmask_high */
237e995d5ccSRichard Henderson /*
238e995d5ccSRichard Henderson * Note that older versions of this feature only contained
239e995d5ccSRichard Henderson * pauth_{d,c}mask, for use with Linux user processes, and
240e995d5ccSRichard Henderson * thus exclusively in the low half of the address space.
241e995d5ccSRichard Henderson *
242e995d5ccSRichard Henderson * To support system mode, and to debug kernels, two new regs
243e995d5ccSRichard Henderson * were added to cover the high half of the address space.
244e995d5ccSRichard Henderson * For the purpose of pauth_ptr_mask, we can use any well-formed
245e995d5ccSRichard Henderson * address within the address space half -- here, 0 and -1.
246e995d5ccSRichard Henderson */
247e995d5ccSRichard Henderson {
248e995d5ccSRichard Henderson bool is_data = !(reg & 1);
249e995d5ccSRichard Henderson bool is_high = reg & 2;
250b15bdc96SPhilippe Mathieu-Daudé ARMMMUIdx mmu_idx = arm_stage1_mmu_idx(env);
251b15bdc96SPhilippe Mathieu-Daudé ARMVAParameters param;
252b15bdc96SPhilippe Mathieu-Daudé
253478dccbbSPeter Maydell param = aa64_va_parameters(env, -is_high, mmu_idx, is_data, false);
254b15bdc96SPhilippe Mathieu-Daudé return gdb_get_reg64(buf, pauth_ptr_mask(param));
255e995d5ccSRichard Henderson }
256e995d5ccSRichard Henderson default:
257e995d5ccSRichard Henderson return 0;
258e995d5ccSRichard Henderson }
259e995d5ccSRichard Henderson }
260e995d5ccSRichard Henderson
aarch64_gdb_set_pauth_reg(CPUState * cs,uint8_t * buf,int reg)26166260159SAkihiko Odaki int aarch64_gdb_set_pauth_reg(CPUState *cs, uint8_t *buf, int reg)
262e995d5ccSRichard Henderson {
263e995d5ccSRichard Henderson /* All pseudo registers are read-only. */
264e995d5ccSRichard Henderson return 0;
265e995d5ccSRichard Henderson }
266e995d5ccSRichard Henderson
output_vector_union_type(GDBFeatureBuilder * builder,int reg_width,const char * name)267690bd97bSAkihiko Odaki static void output_vector_union_type(GDBFeatureBuilder *builder, int reg_width,
26841c9ad8fSRichard Henderson const char *name)
269f214bddeSRichard Henderson {
270e03aba88SRichard Henderson struct TypeSize {
271e03aba88SRichard Henderson const char *gdb_type;
272e03aba88SRichard Henderson short size;
273e03aba88SRichard Henderson char sz, suffix;
274e03aba88SRichard Henderson };
275e03aba88SRichard Henderson
276e03aba88SRichard Henderson static const struct TypeSize vec_lanes[] = {
277e03aba88SRichard Henderson /* quads */
278e03aba88SRichard Henderson { "uint128", 128, 'q', 'u' },
279e03aba88SRichard Henderson { "int128", 128, 'q', 's' },
280e03aba88SRichard Henderson /* 64 bit */
281e03aba88SRichard Henderson { "ieee_double", 64, 'd', 'f' },
282e03aba88SRichard Henderson { "uint64", 64, 'd', 'u' },
283e03aba88SRichard Henderson { "int64", 64, 'd', 's' },
284e03aba88SRichard Henderson /* 32 bit */
285e03aba88SRichard Henderson { "ieee_single", 32, 's', 'f' },
286e03aba88SRichard Henderson { "uint32", 32, 's', 'u' },
287e03aba88SRichard Henderson { "int32", 32, 's', 's' },
288e03aba88SRichard Henderson /* 16 bit */
289e03aba88SRichard Henderson { "ieee_half", 16, 'h', 'f' },
290e03aba88SRichard Henderson { "uint16", 16, 'h', 'u' },
291e03aba88SRichard Henderson { "int16", 16, 'h', 's' },
292e03aba88SRichard Henderson /* bytes */
293e03aba88SRichard Henderson { "uint8", 8, 'b', 'u' },
294e03aba88SRichard Henderson { "int8", 8, 'b', 's' },
295e03aba88SRichard Henderson };
296e03aba88SRichard Henderson
29755f0fc61SRichard Henderson static const char suf[] = { 'b', 'h', 's', 'd', 'q' };
29855f0fc61SRichard Henderson int i, j;
299e03aba88SRichard Henderson
300e03aba88SRichard Henderson /* First define types and totals in a whole VL */
301e03aba88SRichard Henderson for (i = 0; i < ARRAY_SIZE(vec_lanes); i++) {
302690bd97bSAkihiko Odaki gdb_feature_builder_append_tag(
303690bd97bSAkihiko Odaki builder, "<vector id=\"%s%c%c\" type=\"%s\" count=\"%d\"/>",
30441c9ad8fSRichard Henderson name, vec_lanes[i].sz, vec_lanes[i].suffix,
30541c9ad8fSRichard Henderson vec_lanes[i].gdb_type, reg_width / vec_lanes[i].size);
306e03aba88SRichard Henderson }
30741c9ad8fSRichard Henderson
308e03aba88SRichard Henderson /*
309e03aba88SRichard Henderson * Now define a union for each size group containing unsigned and
310e03aba88SRichard Henderson * signed and potentially float versions of each size from 128 to
311e03aba88SRichard Henderson * 8 bits.
312e03aba88SRichard Henderson */
31355f0fc61SRichard Henderson for (i = 0; i < ARRAY_SIZE(suf); i++) {
31455f0fc61SRichard Henderson int bits = 8 << i;
31555f0fc61SRichard Henderson
316690bd97bSAkihiko Odaki gdb_feature_builder_append_tag(builder, "<union id=\"%sn%c\">",
317690bd97bSAkihiko Odaki name, suf[i]);
318e03aba88SRichard Henderson for (j = 0; j < ARRAY_SIZE(vec_lanes); j++) {
319e03aba88SRichard Henderson if (vec_lanes[j].size == bits) {
320690bd97bSAkihiko Odaki gdb_feature_builder_append_tag(
321690bd97bSAkihiko Odaki builder, "<field name=\"%c\" type=\"%s%c%c\"/>",
32241c9ad8fSRichard Henderson vec_lanes[j].suffix, name,
323e03aba88SRichard Henderson vec_lanes[j].sz, vec_lanes[j].suffix);
324e03aba88SRichard Henderson }
325e03aba88SRichard Henderson }
326690bd97bSAkihiko Odaki gdb_feature_builder_append_tag(builder, "</union>");
327e03aba88SRichard Henderson }
32841c9ad8fSRichard Henderson
329e03aba88SRichard Henderson /* And now the final union of unions */
330690bd97bSAkihiko Odaki gdb_feature_builder_append_tag(builder, "<union id=\"%s\">", name);
33155f0fc61SRichard Henderson for (i = ARRAY_SIZE(suf) - 1; i >= 0; i--) {
332690bd97bSAkihiko Odaki gdb_feature_builder_append_tag(builder,
333690bd97bSAkihiko Odaki "<field name=\"%c\" type=\"%sn%c\"/>",
33441c9ad8fSRichard Henderson suf[i], name, suf[i]);
335e03aba88SRichard Henderson }
336690bd97bSAkihiko Odaki gdb_feature_builder_append_tag(builder, "</union>");
337f214bddeSRichard Henderson }
338f214bddeSRichard Henderson
arm_gen_dynamic_svereg_feature(CPUState * cs,int base_reg)339690bd97bSAkihiko Odaki GDBFeature *arm_gen_dynamic_svereg_feature(CPUState *cs, int base_reg)
340f214bddeSRichard Henderson {
341f214bddeSRichard Henderson ARMCPU *cpu = ARM_CPU(cs);
342a1ad913dSRichard Henderson int reg_width = cpu->sve_max_vq * 128;
3435cd5fa75SRichard Henderson int pred_width = cpu->sve_max_vq * 16;
344690bd97bSAkihiko Odaki GDBFeatureBuilder builder;
345690bd97bSAkihiko Odaki char *name;
346690bd97bSAkihiko Odaki int reg = 0;
347a1ad913dSRichard Henderson int i;
348a1ad913dSRichard Henderson
349690bd97bSAkihiko Odaki gdb_feature_builder_init(&builder, &cpu->dyn_svereg_feature.desc,
350690bd97bSAkihiko Odaki "org.gnu.gdb.aarch64.sve", "sve-registers.xml",
351690bd97bSAkihiko Odaki base_reg);
352f214bddeSRichard Henderson
353a1ad913dSRichard Henderson /* Create the vector union type. */
354690bd97bSAkihiko Odaki output_vector_union_type(&builder, reg_width, "svev");
355e03aba88SRichard Henderson
356a1ad913dSRichard Henderson /* Create the predicate vector type. */
357690bd97bSAkihiko Odaki gdb_feature_builder_append_tag(
358690bd97bSAkihiko Odaki &builder, "<vector id=\"svep\" type=\"uint8\" count=\"%d\"/>",
359fdfb214cSRichard Henderson pred_width / 8);
360e03aba88SRichard Henderson
361a1ad913dSRichard Henderson /* Define the vector registers. */
362e03aba88SRichard Henderson for (i = 0; i < 32; i++) {
363690bd97bSAkihiko Odaki name = g_strdup_printf("z%d", i);
364690bd97bSAkihiko Odaki gdb_feature_builder_append_reg(&builder, name, reg_width, reg++,
365690bd97bSAkihiko Odaki "svev", NULL);
366e03aba88SRichard Henderson }
367a1ad913dSRichard Henderson
368e03aba88SRichard Henderson /* fpscr & status registers */
369690bd97bSAkihiko Odaki gdb_feature_builder_append_reg(&builder, "fpsr", 32, reg++,
370690bd97bSAkihiko Odaki "int", "float");
371690bd97bSAkihiko Odaki gdb_feature_builder_append_reg(&builder, "fpcr", 32, reg++,
372690bd97bSAkihiko Odaki "int", "float");
373e03aba88SRichard Henderson
374a1ad913dSRichard Henderson /* Define the predicate registers. */
375e03aba88SRichard Henderson for (i = 0; i < 16; i++) {
376690bd97bSAkihiko Odaki name = g_strdup_printf("p%d", i);
377690bd97bSAkihiko Odaki gdb_feature_builder_append_reg(&builder, name, pred_width, reg++,
378690bd97bSAkihiko Odaki "svep", NULL);
379e03aba88SRichard Henderson }
380690bd97bSAkihiko Odaki gdb_feature_builder_append_reg(&builder, "ffr", pred_width, reg++,
381690bd97bSAkihiko Odaki "svep", "vector");
382a1ad913dSRichard Henderson
383a1ad913dSRichard Henderson /* Define the vector length pseudo-register. */
384690bd97bSAkihiko Odaki gdb_feature_builder_append_reg(&builder, "vg", 64, reg++, "int", NULL);
385e03aba88SRichard Henderson
386690bd97bSAkihiko Odaki gdb_feature_builder_end(&builder);
387a1ad913dSRichard Henderson
388690bd97bSAkihiko Odaki return &cpu->dyn_svereg_feature.desc;
389e03aba88SRichard Henderson }
390f81198ceSGustavo Romero
391f81198ceSGustavo Romero #ifdef CONFIG_USER_ONLY
aarch64_gdb_get_tag_ctl_reg(CPUState * cs,GByteArray * buf,int reg)392f81198ceSGustavo Romero int aarch64_gdb_get_tag_ctl_reg(CPUState *cs, GByteArray *buf, int reg)
393f81198ceSGustavo Romero {
394f81198ceSGustavo Romero ARMCPU *cpu = ARM_CPU(cs);
395f81198ceSGustavo Romero CPUARMState *env = &cpu->env;
396f81198ceSGustavo Romero uint64_t tcf0;
397f81198ceSGustavo Romero
398f81198ceSGustavo Romero assert(reg == 0);
399f81198ceSGustavo Romero
400f81198ceSGustavo Romero tcf0 = extract64(env->cp15.sctlr_el[1], 38, 2);
401f81198ceSGustavo Romero
402f81198ceSGustavo Romero return gdb_get_reg64(buf, tcf0);
403f81198ceSGustavo Romero }
404f81198ceSGustavo Romero
aarch64_gdb_set_tag_ctl_reg(CPUState * cs,uint8_t * buf,int reg)405f81198ceSGustavo Romero int aarch64_gdb_set_tag_ctl_reg(CPUState *cs, uint8_t *buf, int reg)
406f81198ceSGustavo Romero {
4071c687f65SWarner Losh #if defined(CONFIG_LINUX)
408f81198ceSGustavo Romero ARMCPU *cpu = ARM_CPU(cs);
409f81198ceSGustavo Romero CPUARMState *env = &cpu->env;
410f81198ceSGustavo Romero
411f81198ceSGustavo Romero uint8_t tcf;
412f81198ceSGustavo Romero
413f81198ceSGustavo Romero assert(reg == 0);
414f81198ceSGustavo Romero
415f81198ceSGustavo Romero tcf = *buf << PR_MTE_TCF_SHIFT;
416f81198ceSGustavo Romero
417f81198ceSGustavo Romero if (!tcf) {
418f81198ceSGustavo Romero return 0;
419f81198ceSGustavo Romero }
420f81198ceSGustavo Romero
421f81198ceSGustavo Romero /*
422f81198ceSGustavo Romero * 'tag_ctl' register is actually a "pseudo-register" provided by GDB to
423f81198ceSGustavo Romero * expose options regarding the type of MTE fault that can be controlled at
424f81198ceSGustavo Romero * runtime.
425f81198ceSGustavo Romero */
426f81198ceSGustavo Romero arm_set_mte_tcf0(env, tcf);
427f81198ceSGustavo Romero
428f81198ceSGustavo Romero return 1;
4291c687f65SWarner Losh #else
4301c687f65SWarner Losh return 0;
4311c687f65SWarner Losh #endif
432f81198ceSGustavo Romero }
433*0298229aSGustavo Romero #endif /* CONFIG_USER_ONLY */
434f81198ceSGustavo Romero
435*0298229aSGustavo Romero #ifdef CONFIG_TCG
handle_q_memtag(GArray * params,void * user_ctx)436f81198ceSGustavo Romero static void handle_q_memtag(GArray *params, void *user_ctx)
437f81198ceSGustavo Romero {
438f81198ceSGustavo Romero ARMCPU *cpu = ARM_CPU(user_ctx);
439f81198ceSGustavo Romero CPUARMState *env = &cpu->env;
440f6110605SGustavo Romero uint32_t mmu_index;
441f81198ceSGustavo Romero
442f81198ceSGustavo Romero uint64_t addr = gdb_get_cmd_param(params, 0)->val_ull;
443f81198ceSGustavo Romero uint64_t len = gdb_get_cmd_param(params, 1)->val_ul;
444f81198ceSGustavo Romero int type = gdb_get_cmd_param(params, 2)->val_ul;
445f81198ceSGustavo Romero
446f81198ceSGustavo Romero uint8_t *tags;
447f81198ceSGustavo Romero uint8_t addr_tag;
448f81198ceSGustavo Romero
449f81198ceSGustavo Romero g_autoptr(GString) str_buf = g_string_new(NULL);
450f81198ceSGustavo Romero
451f81198ceSGustavo Romero /*
452f81198ceSGustavo Romero * GDB does not query multiple tags for a memory range on remote targets, so
453f81198ceSGustavo Romero * that's not supported either by gdbstub.
454f81198ceSGustavo Romero */
455f81198ceSGustavo Romero if (len != 1) {
456f81198ceSGustavo Romero gdb_put_packet("E02");
457f81198ceSGustavo Romero }
458f81198ceSGustavo Romero
459f81198ceSGustavo Romero /* GDB never queries a tag different from an allocation tag (type 1). */
460f81198ceSGustavo Romero if (type != 1) {
461f81198ceSGustavo Romero gdb_put_packet("E03");
462f81198ceSGustavo Romero }
463f81198ceSGustavo Romero
464f6110605SGustavo Romero /* Find out the current translation regime for probe. */
465f6110605SGustavo Romero mmu_index = cpu_mmu_index(env_cpu(env), false);
466f81198ceSGustavo Romero /* Note that tags are packed here (2 tags packed in one byte). */
467f6110605SGustavo Romero tags = allocation_tag_mem_probe(env, mmu_index, addr, MMU_DATA_LOAD, 1,
468f81198ceSGustavo Romero MMU_DATA_LOAD, true, 0);
469f81198ceSGustavo Romero if (!tags) {
470f81198ceSGustavo Romero /* Address is not in a tagged region. */
471f81198ceSGustavo Romero gdb_put_packet("E04");
472f81198ceSGustavo Romero return;
473f81198ceSGustavo Romero }
474f81198ceSGustavo Romero
475f81198ceSGustavo Romero /* Unpack tag from byte. */
476f81198ceSGustavo Romero addr_tag = load_tag1(addr, tags);
477f81198ceSGustavo Romero g_string_printf(str_buf, "m%.2x", addr_tag);
478f81198ceSGustavo Romero
479f81198ceSGustavo Romero gdb_put_packet(str_buf->str);
480f81198ceSGustavo Romero }
481f81198ceSGustavo Romero
handle_q_isaddresstagged(GArray * params,void * user_ctx)482f81198ceSGustavo Romero static void handle_q_isaddresstagged(GArray *params, void *user_ctx)
483f81198ceSGustavo Romero {
484f81198ceSGustavo Romero ARMCPU *cpu = ARM_CPU(user_ctx);
485f81198ceSGustavo Romero CPUARMState *env = &cpu->env;
486f6110605SGustavo Romero uint32_t mmu_index;
487f81198ceSGustavo Romero
488f81198ceSGustavo Romero uint64_t addr = gdb_get_cmd_param(params, 0)->val_ull;
489f81198ceSGustavo Romero
490f81198ceSGustavo Romero uint8_t *tags;
491f81198ceSGustavo Romero const char *reply;
492f81198ceSGustavo Romero
493f6110605SGustavo Romero /* Find out the current translation regime for probe. */
494f6110605SGustavo Romero mmu_index = cpu_mmu_index(env_cpu(env), false);
495f6110605SGustavo Romero tags = allocation_tag_mem_probe(env, mmu_index, addr, MMU_DATA_LOAD, 1,
496f81198ceSGustavo Romero MMU_DATA_LOAD, true, 0);
497f81198ceSGustavo Romero reply = tags ? "01" : "00";
498f81198ceSGustavo Romero
499f81198ceSGustavo Romero gdb_put_packet(reply);
500f81198ceSGustavo Romero }
501f81198ceSGustavo Romero
handle_Q_memtag(GArray * params,void * user_ctx)502f81198ceSGustavo Romero static void handle_Q_memtag(GArray *params, void *user_ctx)
503f81198ceSGustavo Romero {
504f81198ceSGustavo Romero ARMCPU *cpu = ARM_CPU(user_ctx);
505f81198ceSGustavo Romero CPUARMState *env = &cpu->env;
506f6110605SGustavo Romero uint32_t mmu_index;
507f81198ceSGustavo Romero
508f81198ceSGustavo Romero uint64_t start_addr = gdb_get_cmd_param(params, 0)->val_ull;
509f81198ceSGustavo Romero uint64_t len = gdb_get_cmd_param(params, 1)->val_ul;
510f81198ceSGustavo Romero int type = gdb_get_cmd_param(params, 2)->val_ul;
511f81198ceSGustavo Romero char const *new_tags_str = gdb_get_cmd_param(params, 3)->data;
512f81198ceSGustavo Romero
513f81198ceSGustavo Romero uint64_t end_addr;
514f81198ceSGustavo Romero
515f81198ceSGustavo Romero int num_new_tags;
516f81198ceSGustavo Romero uint8_t *tags;
517f81198ceSGustavo Romero
518f81198ceSGustavo Romero g_autoptr(GByteArray) new_tags = g_byte_array_new();
519f81198ceSGustavo Romero
520f81198ceSGustavo Romero /*
521f81198ceSGustavo Romero * Only the allocation tag (i.e. type 1) can be set at the stub side.
522f81198ceSGustavo Romero */
523f81198ceSGustavo Romero if (type != 1) {
524f81198ceSGustavo Romero gdb_put_packet("E02");
525f81198ceSGustavo Romero return;
526f81198ceSGustavo Romero }
527f81198ceSGustavo Romero
528f81198ceSGustavo Romero end_addr = start_addr + (len - 1); /* 'len' is always >= 1 */
529f81198ceSGustavo Romero /* Check if request's memory range does not cross page boundaries. */
530f81198ceSGustavo Romero if ((start_addr ^ end_addr) & TARGET_PAGE_MASK) {
531f81198ceSGustavo Romero gdb_put_packet("E03");
532f81198ceSGustavo Romero return;
533f81198ceSGustavo Romero }
534f81198ceSGustavo Romero
535f81198ceSGustavo Romero /*
536f81198ceSGustavo Romero * Get all tags in the page starting from the tag of the start address.
537f81198ceSGustavo Romero * Note that there are two tags packed into a single byte here.
538f81198ceSGustavo Romero */
539f6110605SGustavo Romero /* Find out the current translation regime for probe. */
540f6110605SGustavo Romero mmu_index = cpu_mmu_index(env_cpu(env), false);
541f6110605SGustavo Romero tags = allocation_tag_mem_probe(env, mmu_index, start_addr, MMU_DATA_STORE,
542f6110605SGustavo Romero 1, MMU_DATA_STORE, true, 0);
543f81198ceSGustavo Romero if (!tags) {
544f81198ceSGustavo Romero /* Address is not in a tagged region. */
545f81198ceSGustavo Romero gdb_put_packet("E04");
546f81198ceSGustavo Romero return;
547f81198ceSGustavo Romero }
548f81198ceSGustavo Romero
549f81198ceSGustavo Romero /* Convert tags provided by GDB, 2 hex digits per tag. */
550f81198ceSGustavo Romero num_new_tags = strlen(new_tags_str) / 2;
551f81198ceSGustavo Romero gdb_hextomem(new_tags, new_tags_str, num_new_tags);
552f81198ceSGustavo Romero
553f81198ceSGustavo Romero uint64_t address = start_addr;
554f81198ceSGustavo Romero int new_tag_index = 0;
555f81198ceSGustavo Romero while (address <= end_addr) {
556f81198ceSGustavo Romero uint8_t new_tag;
557f81198ceSGustavo Romero int packed_index;
558f81198ceSGustavo Romero
559f81198ceSGustavo Romero /*
560f81198ceSGustavo Romero * Find packed tag index from unpacked tag index. There are two tags
561f81198ceSGustavo Romero * in one packed index (one tag per nibble).
562f81198ceSGustavo Romero */
563f81198ceSGustavo Romero packed_index = new_tag_index / 2;
564f81198ceSGustavo Romero
565f81198ceSGustavo Romero new_tag = new_tags->data[new_tag_index % num_new_tags];
566f81198ceSGustavo Romero store_tag1(address, tags + packed_index, new_tag);
567f81198ceSGustavo Romero
568f81198ceSGustavo Romero address += TAG_GRANULE;
569f81198ceSGustavo Romero new_tag_index++;
570f81198ceSGustavo Romero }
571f81198ceSGustavo Romero
572f81198ceSGustavo Romero gdb_put_packet("OK");
573f81198ceSGustavo Romero }
574f81198ceSGustavo Romero
575f81198ceSGustavo Romero enum Command {
576f81198ceSGustavo Romero qMemTags,
577f81198ceSGustavo Romero qIsAddressTagged,
578f81198ceSGustavo Romero QMemTags,
579f81198ceSGustavo Romero NUM_CMDS
580f81198ceSGustavo Romero };
581f81198ceSGustavo Romero
582e8122a71SAlex Bennée static const GdbCmdParseEntry cmd_handler_table[NUM_CMDS] = {
583f81198ceSGustavo Romero [qMemTags] = {
584f81198ceSGustavo Romero .handler = handle_q_memtag,
585f81198ceSGustavo Romero .cmd_startswith = true,
586f81198ceSGustavo Romero .cmd = "MemTags:",
587f81198ceSGustavo Romero .schema = "L,l:l0",
588f81198ceSGustavo Romero .need_cpu_context = true
589f81198ceSGustavo Romero },
590f81198ceSGustavo Romero [qIsAddressTagged] = {
591f81198ceSGustavo Romero .handler = handle_q_isaddresstagged,
592f81198ceSGustavo Romero .cmd_startswith = true,
593f81198ceSGustavo Romero .cmd = "IsAddressTagged:",
594f81198ceSGustavo Romero .schema = "L0",
595f81198ceSGustavo Romero .need_cpu_context = true
596f81198ceSGustavo Romero },
597f81198ceSGustavo Romero [QMemTags] = {
598f81198ceSGustavo Romero .handler = handle_Q_memtag,
599f81198ceSGustavo Romero .cmd_startswith = true,
600f81198ceSGustavo Romero .cmd = "MemTags:",
601f81198ceSGustavo Romero .schema = "L,l:l:s0",
602f81198ceSGustavo Romero .need_cpu_context = true
603f81198ceSGustavo Romero },
604f81198ceSGustavo Romero };
605*0298229aSGustavo Romero #endif /* CONFIG_TCG */
606f81198ceSGustavo Romero
aarch64_cpu_register_gdb_commands(ARMCPU * cpu,GString * qsupported,GPtrArray * qtable,GPtrArray * stable)607f81198ceSGustavo Romero void aarch64_cpu_register_gdb_commands(ARMCPU *cpu, GString *qsupported,
608e8122a71SAlex Bennée GPtrArray *qtable, GPtrArray *stable)
609f81198ceSGustavo Romero {
610f81198ceSGustavo Romero /* MTE */
611*0298229aSGustavo Romero #ifdef CONFIG_TCG
612f81198ceSGustavo Romero if (cpu_isar_feature(aa64_mte, cpu)) {
613f81198ceSGustavo Romero g_string_append(qsupported, ";memory-tagging+");
614f81198ceSGustavo Romero
615e8122a71SAlex Bennée g_ptr_array_add(qtable, (gpointer) &cmd_handler_table[qMemTags]);
616e8122a71SAlex Bennée g_ptr_array_add(qtable, (gpointer) &cmd_handler_table[qIsAddressTagged]);
617e8122a71SAlex Bennée g_ptr_array_add(stable, (gpointer) &cmd_handler_table[QMemTags]);
618f81198ceSGustavo Romero }
619f81198ceSGustavo Romero #endif
620f81198ceSGustavo Romero }
621