]>
Commit | Line | Data |
---|---|---|
96c04212 AG |
1 | /* |
2 | * ARM gdb server stub: AArch64 specific functions. | |
3 | * | |
4 | * Copyright (c) 2013 SUSE LINUX Products GmbH | |
5 | * | |
6 | * This library is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU Lesser General Public | |
8 | * License as published by the Free Software Foundation; either | |
50f57e09 | 9 | * version 2.1 of the License, or (at your option) any later version. |
96c04212 AG |
10 | * |
11 | * This library is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * Lesser General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU Lesser General Public | |
17 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. | |
18 | */ | |
74c21bd0 | 19 | #include "qemu/osdep.h" |
89f4f20e | 20 | #include "qemu/log.h" |
33c11879 | 21 | #include "cpu.h" |
89f4f20e | 22 | #include "internals.h" |
96c04212 AG |
23 | #include "exec/gdbstub.h" |
24 | ||
a010bdbe | 25 | int aarch64_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) |
96c04212 AG |
26 | { |
27 | ARMCPU *cpu = ARM_CPU(cs); | |
28 | CPUARMState *env = &cpu->env; | |
29 | ||
30 | if (n < 31) { | |
31 | /* Core integer register. */ | |
32 | return gdb_get_reg64(mem_buf, env->xregs[n]); | |
33 | } | |
34 | switch (n) { | |
35 | case 31: | |
36 | return gdb_get_reg64(mem_buf, env->xregs[31]); | |
96c04212 AG |
37 | case 32: |
38 | return gdb_get_reg64(mem_buf, env->pc); | |
96c04212 | 39 | case 33: |
d356312f | 40 | return gdb_get_reg32(mem_buf, pstate_read(env)); |
96c04212 AG |
41 | } |
42 | /* Unknown register. */ | |
43 | return 0; | |
44 | } | |
45 | ||
46 | int aarch64_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) | |
47 | { | |
48 | ARMCPU *cpu = ARM_CPU(cs); | |
49 | CPUARMState *env = &cpu->env; | |
50 | uint64_t tmp; | |
51 | ||
52 | tmp = ldq_p(mem_buf); | |
53 | ||
54 | if (n < 31) { | |
55 | /* Core integer register. */ | |
56 | env->xregs[n] = tmp; | |
57 | return 8; | |
58 | } | |
59 | switch (n) { | |
60 | case 31: | |
61 | env->xregs[31] = tmp; | |
62 | return 8; | |
63 | case 32: | |
64 | env->pc = tmp; | |
65 | return 8; | |
66 | case 33: | |
67 | /* CPSR */ | |
d356312f | 68 | pstate_write(env, tmp); |
96c04212 AG |
69 | return 4; |
70 | } | |
71 | /* Unknown register. */ | |
72 | return 0; | |
73 | } | |
89f4f20e | 74 | |
963a6b91 | 75 | int aarch64_gdb_get_fpu_reg(CPUARMState *env, GByteArray *buf, int reg) |
89f4f20e PM |
76 | { |
77 | switch (reg) { | |
78 | case 0 ... 31: | |
79 | { | |
80 | /* 128 bit FP register - quads are in LE order */ | |
81 | uint64_t *q = aa64_vfp_qreg(env, reg); | |
82 | return gdb_get_reg128(buf, q[1], q[0]); | |
83 | } | |
84 | case 32: | |
85 | /* FPSR */ | |
86 | return gdb_get_reg32(buf, vfp_get_fpsr(env)); | |
87 | case 33: | |
88 | /* FPCR */ | |
89 | return gdb_get_reg32(buf, vfp_get_fpcr(env)); | |
90 | default: | |
91 | return 0; | |
92 | } | |
93 | } | |
94 | ||
963a6b91 | 95 | int aarch64_gdb_set_fpu_reg(CPUARMState *env, uint8_t *buf, int reg) |
89f4f20e PM |
96 | { |
97 | switch (reg) { | |
98 | case 0 ... 31: | |
99 | /* 128 bit FP register */ | |
100 | { | |
101 | uint64_t *q = aa64_vfp_qreg(env, reg); | |
102 | q[0] = ldq_le_p(buf); | |
103 | q[1] = ldq_le_p(buf + 8); | |
104 | return 16; | |
105 | } | |
106 | case 32: | |
107 | /* FPSR */ | |
108 | vfp_set_fpsr(env, ldl_p(buf)); | |
109 | return 4; | |
110 | case 33: | |
111 | /* FPCR */ | |
112 | vfp_set_fpcr(env, ldl_p(buf)); | |
113 | return 4; | |
114 | default: | |
115 | return 0; | |
116 | } | |
117 | } | |
118 | ||
963a6b91 | 119 | int aarch64_gdb_get_sve_reg(CPUARMState *env, GByteArray *buf, int reg) |
89f4f20e PM |
120 | { |
121 | ARMCPU *cpu = env_archcpu(env); | |
122 | ||
123 | switch (reg) { | |
124 | /* The first 32 registers are the zregs */ | |
125 | case 0 ... 31: | |
126 | { | |
127 | int vq, len = 0; | |
128 | for (vq = 0; vq < cpu->sve_max_vq; vq++) { | |
129 | len += gdb_get_reg128(buf, | |
130 | env->vfp.zregs[reg].d[vq * 2 + 1], | |
131 | env->vfp.zregs[reg].d[vq * 2]); | |
132 | } | |
133 | return len; | |
134 | } | |
135 | case 32: | |
136 | return gdb_get_reg32(buf, vfp_get_fpsr(env)); | |
137 | case 33: | |
138 | return gdb_get_reg32(buf, vfp_get_fpcr(env)); | |
139 | /* then 16 predicates and the ffr */ | |
140 | case 34 ... 50: | |
141 | { | |
142 | int preg = reg - 34; | |
143 | int vq, len = 0; | |
144 | for (vq = 0; vq < cpu->sve_max_vq; vq = vq + 4) { | |
145 | len += gdb_get_reg64(buf, env->vfp.pregs[preg].p[vq / 4]); | |
146 | } | |
147 | return len; | |
148 | } | |
149 | case 51: | |
150 | { | |
151 | /* | |
152 | * We report in Vector Granules (VG) which is 64bit in a Z reg | |
153 | * while the ZCR works in Vector Quads (VQ) which is 128bit chunks. | |
154 | */ | |
5ef3cc56 | 155 | int vq = sve_vqm1_for_el(env, arm_current_el(env)) + 1; |
89f4f20e PM |
156 | return gdb_get_reg64(buf, vq * 2); |
157 | } | |
158 | default: | |
159 | /* gdbstub asked for something out our range */ | |
160 | qemu_log_mask(LOG_UNIMP, "%s: out of range register %d", __func__, reg); | |
161 | break; | |
162 | } | |
163 | ||
164 | return 0; | |
165 | } | |
166 | ||
963a6b91 | 167 | int aarch64_gdb_set_sve_reg(CPUARMState *env, uint8_t *buf, int reg) |
89f4f20e PM |
168 | { |
169 | ARMCPU *cpu = env_archcpu(env); | |
170 | ||
171 | /* The first 32 registers are the zregs */ | |
172 | switch (reg) { | |
173 | /* The first 32 registers are the zregs */ | |
174 | case 0 ... 31: | |
175 | { | |
176 | int vq, len = 0; | |
177 | uint64_t *p = (uint64_t *) buf; | |
178 | for (vq = 0; vq < cpu->sve_max_vq; vq++) { | |
179 | env->vfp.zregs[reg].d[vq * 2 + 1] = *p++; | |
180 | env->vfp.zregs[reg].d[vq * 2] = *p++; | |
181 | len += 16; | |
182 | } | |
183 | return len; | |
184 | } | |
185 | case 32: | |
186 | vfp_set_fpsr(env, *(uint32_t *)buf); | |
187 | return 4; | |
188 | case 33: | |
189 | vfp_set_fpcr(env, *(uint32_t *)buf); | |
190 | return 4; | |
191 | case 34 ... 50: | |
192 | { | |
193 | int preg = reg - 34; | |
194 | int vq, len = 0; | |
195 | uint64_t *p = (uint64_t *) buf; | |
196 | for (vq = 0; vq < cpu->sve_max_vq; vq = vq + 4) { | |
197 | env->vfp.pregs[preg].p[vq / 4] = *p++; | |
198 | len += 8; | |
199 | } | |
200 | return len; | |
201 | } | |
202 | case 51: | |
203 | /* cannot set vg via gdbstub */ | |
204 | return 0; | |
205 | default: | |
206 | /* gdbstub asked for something out our range */ | |
207 | break; | |
208 | } | |
209 | ||
210 | return 0; | |
211 | } | |
e03aba88 RH |
212 | |
213 | struct TypeSize { | |
214 | const char *gdb_type; | |
215 | short size; | |
216 | char sz, suffix; | |
217 | }; | |
218 | ||
219 | static const struct TypeSize vec_lanes[] = { | |
220 | /* quads */ | |
221 | { "uint128", 128, 'q', 'u' }, | |
222 | { "int128", 128, 'q', 's' }, | |
223 | /* 64 bit */ | |
224 | { "ieee_double", 64, 'd', 'f' }, | |
225 | { "uint64", 64, 'd', 'u' }, | |
226 | { "int64", 64, 'd', 's' }, | |
227 | /* 32 bit */ | |
228 | { "ieee_single", 32, 's', 'f' }, | |
229 | { "uint32", 32, 's', 'u' }, | |
230 | { "int32", 32, 's', 's' }, | |
231 | /* 16 bit */ | |
232 | { "ieee_half", 16, 'h', 'f' }, | |
233 | { "uint16", 16, 'h', 'u' }, | |
234 | { "int16", 16, 'h', 's' }, | |
235 | /* bytes */ | |
236 | { "uint8", 8, 'b', 'u' }, | |
237 | { "int8", 8, 'b', 's' }, | |
238 | }; | |
239 | ||
240 | int arm_gen_dynamic_svereg_xml(CPUState *cs, int base_reg) | |
241 | { | |
242 | ARMCPU *cpu = ARM_CPU(cs); | |
243 | GString *s = g_string_new(NULL); | |
244 | DynamicGDBXMLInfo *info = &cpu->dyn_svereg_xml; | |
245 | g_autoptr(GString) ts = g_string_new(""); | |
246 | int i, j, bits, reg_width = (cpu->sve_max_vq * 128); | |
247 | info->num = 0; | |
248 | g_string_printf(s, "<?xml version=\"1.0\"?>"); | |
249 | g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">"); | |
250 | g_string_append_printf(s, "<feature name=\"org.gnu.gdb.aarch64.sve\">"); | |
251 | ||
252 | /* First define types and totals in a whole VL */ | |
253 | for (i = 0; i < ARRAY_SIZE(vec_lanes); i++) { | |
254 | int count = reg_width / vec_lanes[i].size; | |
255 | g_string_printf(ts, "svev%c%c", vec_lanes[i].sz, vec_lanes[i].suffix); | |
256 | g_string_append_printf(s, | |
257 | "<vector id=\"%s\" type=\"%s\" count=\"%d\"/>", | |
258 | ts->str, vec_lanes[i].gdb_type, count); | |
259 | } | |
260 | /* | |
261 | * Now define a union for each size group containing unsigned and | |
262 | * signed and potentially float versions of each size from 128 to | |
263 | * 8 bits. | |
264 | */ | |
265 | for (bits = 128, i = 0; bits >= 8; bits /= 2, i++) { | |
266 | const char suf[] = { 'q', 'd', 's', 'h', 'b' }; | |
267 | g_string_append_printf(s, "<union id=\"svevn%c\">", suf[i]); | |
268 | for (j = 0; j < ARRAY_SIZE(vec_lanes); j++) { | |
269 | if (vec_lanes[j].size == bits) { | |
270 | g_string_append_printf(s, "<field name=\"%c\" type=\"svev%c%c\"/>", | |
271 | vec_lanes[j].suffix, | |
272 | vec_lanes[j].sz, vec_lanes[j].suffix); | |
273 | } | |
274 | } | |
275 | g_string_append(s, "</union>"); | |
276 | } | |
277 | /* And now the final union of unions */ | |
278 | g_string_append(s, "<union id=\"svev\">"); | |
279 | for (bits = 128, i = 0; bits >= 8; bits /= 2, i++) { | |
280 | const char suf[] = { 'q', 'd', 's', 'h', 'b' }; | |
281 | g_string_append_printf(s, "<field name=\"%c\" type=\"svevn%c\"/>", | |
282 | suf[i], suf[i]); | |
283 | } | |
284 | g_string_append(s, "</union>"); | |
285 | ||
286 | /* Finally the sve prefix type */ | |
287 | g_string_append_printf(s, | |
288 | "<vector id=\"svep\" type=\"uint8\" count=\"%d\"/>", | |
289 | reg_width / 8); | |
290 | ||
291 | /* Then define each register in parts for each vq */ | |
292 | for (i = 0; i < 32; i++) { | |
293 | g_string_append_printf(s, | |
294 | "<reg name=\"z%d\" bitsize=\"%d\"" | |
295 | " regnum=\"%d\" type=\"svev\"/>", | |
296 | i, reg_width, base_reg++); | |
297 | info->num++; | |
298 | } | |
299 | /* fpscr & status registers */ | |
300 | g_string_append_printf(s, "<reg name=\"fpsr\" bitsize=\"32\"" | |
301 | " regnum=\"%d\" group=\"float\"" | |
302 | " type=\"int\"/>", base_reg++); | |
303 | g_string_append_printf(s, "<reg name=\"fpcr\" bitsize=\"32\"" | |
304 | " regnum=\"%d\" group=\"float\"" | |
305 | " type=\"int\"/>", base_reg++); | |
306 | info->num += 2; | |
307 | ||
308 | for (i = 0; i < 16; i++) { | |
309 | g_string_append_printf(s, | |
310 | "<reg name=\"p%d\" bitsize=\"%d\"" | |
311 | " regnum=\"%d\" type=\"svep\"/>", | |
312 | i, cpu->sve_max_vq * 16, base_reg++); | |
313 | info->num++; | |
314 | } | |
315 | g_string_append_printf(s, | |
316 | "<reg name=\"ffr\" bitsize=\"%d\"" | |
317 | " regnum=\"%d\" group=\"vector\"" | |
318 | " type=\"svep\"/>", | |
319 | cpu->sve_max_vq * 16, base_reg++); | |
320 | g_string_append_printf(s, | |
321 | "<reg name=\"vg\" bitsize=\"64\"" | |
322 | " regnum=\"%d\" type=\"int\"/>", | |
323 | base_reg++); | |
324 | info->num += 2; | |
325 | g_string_append_printf(s, "</feature>"); | |
326 | info->desc = g_string_free(s, false); | |
327 | ||
328 | return info->num; | |
329 | } |