]>
Commit | Line | Data |
---|---|---|
ca65640f | 1 | /* Common native Linux code for the AArch64 scalable extensions: SVE and SME. |
122394f1 | 2 | |
1d506c26 | 3 | Copyright (C) 2018-2024 Free Software Foundation, Inc. |
122394f1 AH |
4 | |
5 | This file is part of GDB. | |
6 | ||
7 | This program is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 3 of the License, or | |
10 | (at your option) any later version. | |
11 | ||
12 | This program is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
19 | ||
20 | #include <sys/utsname.h> | |
21 | #include <sys/uio.h> | |
268a13a5 | 22 | #include "gdbsupport/common-defs.h" |
122394f1 AH |
23 | #include "elf/external.h" |
24 | #include "elf/common.h" | |
6ada909e | 25 | #include "aarch64-scalable-linux-ptrace.h" |
122394f1 | 26 | #include "arch/aarch64.h" |
268a13a5 TT |
27 | #include "gdbsupport/common-regcache.h" |
28 | #include "gdbsupport/byte-vector.h" | |
6afcd2d4 | 29 | #include <endian.h> |
ca65640f LM |
30 | #include "arch/aarch64-scalable-linux.h" |
31 | ||
32 | /* See nat/aarch64-scalable-linux-ptrace.h. */ | |
33 | ||
34 | bool | |
35 | aarch64_has_sve_state (int tid) | |
36 | { | |
37 | struct user_sve_header header; | |
38 | ||
39 | if (!read_sve_header (tid, header)) | |
40 | return false; | |
41 | ||
42 | if ((header.flags & SVE_PT_REGS_SVE) == 0) | |
43 | return false; | |
44 | ||
45 | if (sizeof (header) == header.size) | |
46 | return false; | |
47 | ||
48 | return true; | |
49 | } | |
50 | ||
51 | /* See nat/aarch64-scalable-linux-ptrace.h. */ | |
52 | ||
53 | bool | |
54 | aarch64_has_ssve_state (int tid) | |
55 | { | |
56 | struct user_sve_header header; | |
57 | ||
58 | if (!read_ssve_header (tid, header)) | |
59 | return false; | |
60 | ||
61 | if ((header.flags & SVE_PT_REGS_SVE) == 0) | |
62 | return false; | |
63 | ||
64 | if (sizeof (header) == header.size) | |
65 | return false; | |
66 | ||
67 | return true; | |
68 | } | |
69 | ||
70 | /* See nat/aarch64-scalable-linux-ptrace.h. */ | |
71 | ||
72 | bool | |
73 | aarch64_has_za_state (int tid) | |
74 | { | |
75 | struct user_za_header header; | |
76 | ||
77 | if (!read_za_header (tid, header)) | |
78 | return false; | |
79 | ||
80 | if (sizeof (header) == header.size) | |
81 | return false; | |
82 | ||
83 | return true; | |
84 | } | |
85 | ||
86 | /* See nat/aarch64-scalable-linux-ptrace.h. */ | |
87 | ||
88 | bool | |
89 | read_sve_header (int tid, struct user_sve_header &header) | |
90 | { | |
91 | struct iovec iovec; | |
92 | ||
93 | iovec.iov_len = sizeof (header); | |
94 | iovec.iov_base = &header; | |
95 | ||
96 | if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_SVE, &iovec) < 0) | |
97 | { | |
98 | /* SVE is not supported. */ | |
99 | return false; | |
100 | } | |
101 | return true; | |
102 | } | |
103 | ||
104 | /* See nat/aarch64-scalable-linux-ptrace.h. */ | |
105 | ||
106 | bool | |
107 | write_sve_header (int tid, const struct user_sve_header &header) | |
108 | { | |
109 | struct iovec iovec; | |
110 | ||
111 | iovec.iov_len = sizeof (header); | |
112 | iovec.iov_base = (void *) &header; | |
113 | ||
114 | if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_SVE, &iovec) < 0) | |
115 | { | |
116 | /* SVE is not supported. */ | |
117 | return false; | |
118 | } | |
119 | return true; | |
120 | } | |
121 | ||
122 | /* See nat/aarch64-scalable-linux-ptrace.h. */ | |
123 | ||
124 | bool | |
125 | read_ssve_header (int tid, struct user_sve_header &header) | |
126 | { | |
127 | struct iovec iovec; | |
128 | ||
129 | iovec.iov_len = sizeof (header); | |
130 | iovec.iov_base = &header; | |
131 | ||
132 | if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_SSVE, &iovec) < 0) | |
133 | { | |
134 | /* SSVE is not supported. */ | |
135 | return false; | |
136 | } | |
137 | return true; | |
138 | } | |
139 | ||
140 | /* See nat/aarch64-scalable-linux-ptrace.h. */ | |
141 | ||
142 | bool | |
143 | write_ssve_header (int tid, const struct user_sve_header &header) | |
144 | { | |
145 | struct iovec iovec; | |
146 | ||
147 | iovec.iov_len = sizeof (header); | |
148 | iovec.iov_base = (void *) &header; | |
149 | ||
150 | if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_SSVE, &iovec) < 0) | |
151 | { | |
152 | /* SSVE is not supported. */ | |
153 | return false; | |
154 | } | |
155 | return true; | |
156 | } | |
157 | ||
158 | /* See nat/aarch64-scalable-linux-ptrace.h. */ | |
159 | ||
160 | bool | |
161 | read_za_header (int tid, struct user_za_header &header) | |
162 | { | |
163 | struct iovec iovec; | |
164 | ||
165 | iovec.iov_len = sizeof (header); | |
166 | iovec.iov_base = &header; | |
167 | ||
168 | if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_ZA, &iovec) < 0) | |
169 | { | |
170 | /* ZA is not supported. */ | |
171 | return false; | |
172 | } | |
173 | return true; | |
174 | } | |
175 | ||
176 | /* See nat/aarch64-scalable-linux-ptrace.h. */ | |
177 | ||
178 | bool | |
179 | write_za_header (int tid, const struct user_za_header &header) | |
180 | { | |
181 | struct iovec iovec; | |
182 | ||
183 | iovec.iov_len = sizeof (header); | |
184 | iovec.iov_base = (void *) &header; | |
185 | ||
186 | if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_ZA, &iovec) < 0) | |
187 | { | |
188 | /* ZA is not supported. */ | |
189 | return false; | |
190 | } | |
191 | return true; | |
192 | } | |
193 | ||
194 | /* Given VL, the streaming vector length for SME, return true if it is valid | |
195 | and false otherwise. */ | |
196 | ||
197 | static bool | |
198 | aarch64_sme_vl_valid (size_t vl) | |
199 | { | |
200 | return (vl == 16 || vl == 32 || vl == 64 || vl == 128 || vl == 256); | |
201 | } | |
202 | ||
203 | /* Given VL, the vector length for SVE, return true if it is valid and false | |
204 | otherwise. SVE_state is true when the check is for the SVE register set. | |
205 | Otherwise the check is for the SSVE register set. */ | |
206 | ||
207 | static bool | |
208 | aarch64_sve_vl_valid (const bool sve_state, size_t vl) | |
209 | { | |
210 | if (sve_state) | |
211 | return sve_vl_valid (vl); | |
212 | ||
213 | /* We have an active SSVE state, where the valid vector length values are | |
214 | more restrictive. */ | |
215 | return aarch64_sme_vl_valid (vl); | |
216 | } | |
e9902bfc | 217 | |
6ada909e | 218 | /* See nat/aarch64-scalable-linux-ptrace.h. */ |
122394f1 | 219 | |
39bfb937 | 220 | uint64_t |
122394f1 AH |
221 | aarch64_sve_get_vq (int tid) |
222 | { | |
223 | struct iovec iovec; | |
224 | struct user_sve_header header; | |
122394f1 AH |
225 | iovec.iov_len = sizeof (header); |
226 | iovec.iov_base = &header; | |
227 | ||
ca65640f LM |
228 | /* Figure out which register set to use for the request. The vector length |
229 | for SVE can be different from the vector length for SSVE. */ | |
230 | bool has_sve_state = !aarch64_has_ssve_state (tid); | |
231 | if (ptrace (PTRACE_GETREGSET, tid, has_sve_state? NT_ARM_SVE : NT_ARM_SSVE, | |
232 | &iovec) < 0) | |
122394f1 AH |
233 | { |
234 | /* SVE is not supported. */ | |
235 | return 0; | |
236 | } | |
237 | ||
ca65640f LM |
238 | /* Ptrace gives the vector length in bytes. Convert it to VQ, the number of |
239 | 128bit chunks in a Z register. We use VQ because 128 bits is the minimum | |
240 | a Z register can increase in size. */ | |
e9902bfc | 241 | uint64_t vq = sve_vq_from_vl (header.vl); |
122394f1 | 242 | |
ca65640f | 243 | if (!aarch64_sve_vl_valid (has_sve_state, header.vl)) |
122394f1 AH |
244 | { |
245 | warning (_("Invalid SVE state from kernel; SVE disabled.")); | |
246 | return 0; | |
247 | } | |
248 | ||
249 | return vq; | |
250 | } | |
e9902bfc | 251 | |
6ada909e | 252 | /* See nat/aarch64-scalable-linux-ptrace.h. */ |
e9902bfc | 253 | |
48574d91 AH |
254 | bool |
255 | aarch64_sve_set_vq (int tid, uint64_t vq) | |
256 | { | |
257 | struct iovec iovec; | |
258 | struct user_sve_header header; | |
259 | ||
260 | iovec.iov_len = sizeof (header); | |
261 | iovec.iov_base = &header; | |
262 | ||
ca65640f LM |
263 | /* Figure out which register set to use for the request. The vector length |
264 | for SVE can be different from the vector length for SSVE. */ | |
265 | bool has_sve_state = !aarch64_has_ssve_state (tid); | |
266 | if (ptrace (PTRACE_GETREGSET, tid, has_sve_state? NT_ARM_SVE : NT_ARM_SSVE, | |
267 | &iovec) < 0) | |
48574d91 | 268 | { |
ca65640f | 269 | /* SVE/SSVE is not supported. */ |
48574d91 AH |
270 | return false; |
271 | } | |
272 | ||
273 | header.vl = sve_vl_from_vq (vq); | |
274 | ||
ca65640f LM |
275 | if (ptrace (PTRACE_SETREGSET, tid, has_sve_state? NT_ARM_SVE : NT_ARM_SSVE, |
276 | &iovec) < 0) | |
48574d91 AH |
277 | { |
278 | /* Vector length change failed. */ | |
279 | return false; | |
280 | } | |
281 | ||
282 | return true; | |
283 | } | |
284 | ||
6ada909e | 285 | /* See nat/aarch64-scalable-linux-ptrace.h. */ |
48574d91 AH |
286 | |
287 | bool | |
288 | aarch64_sve_set_vq (int tid, struct reg_buffer_common *reg_buf) | |
289 | { | |
2d07da27 LM |
290 | uint64_t reg_vg = 0; |
291 | ||
292 | /* The VG register may not be valid if we've not collected any value yet. | |
293 | This can happen, for example, if we're restoring the regcache after an | |
294 | inferior function call, and the VG register comes after the Z | |
295 | registers. */ | |
48574d91 | 296 | if (reg_buf->get_register_status (AARCH64_SVE_VG_REGNUM) != REG_VALID) |
01add95b SM |
297 | { |
298 | /* If vg is not available yet, fetch it from ptrace. The VG value from | |
299 | ptrace is likely the correct one. */ | |
300 | uint64_t vq = aarch64_sve_get_vq (tid); | |
48574d91 | 301 | |
01add95b SM |
302 | /* If something went wrong, just bail out. */ |
303 | if (vq == 0) | |
304 | return false; | |
2d07da27 | 305 | |
01add95b SM |
306 | reg_vg = sve_vg_from_vq (vq); |
307 | } | |
2d07da27 LM |
308 | else |
309 | reg_buf->raw_collect (AARCH64_SVE_VG_REGNUM, ®_vg); | |
48574d91 AH |
310 | |
311 | return aarch64_sve_set_vq (tid, sve_vq_from_vg (reg_vg)); | |
312 | } | |
313 | ||
6ada909e | 314 | /* See nat/aarch64-scalable-linux-ptrace.h. */ |
48574d91 | 315 | |
ca65640f LM |
316 | uint64_t |
317 | aarch64_za_get_svq (int tid) | |
318 | { | |
319 | struct user_za_header header; | |
320 | if (!read_za_header (tid, header)) | |
321 | return 0; | |
322 | ||
323 | uint64_t vq = sve_vq_from_vl (header.vl); | |
324 | ||
325 | if (!aarch64_sve_vl_valid (false, header.vl)) | |
326 | { | |
327 | warning (_("Invalid ZA state from kernel; ZA disabled.")); | |
328 | return 0; | |
329 | } | |
330 | ||
331 | return vq; | |
332 | } | |
333 | ||
334 | /* See nat/aarch64-scalable-linux-ptrace.h. */ | |
335 | ||
336 | bool | |
337 | aarch64_za_set_svq (int tid, uint64_t vq) | |
338 | { | |
339 | struct iovec iovec; | |
340 | ||
341 | /* Read the NT_ARM_ZA header. */ | |
342 | struct user_za_header header; | |
343 | if (!read_za_header (tid, header)) | |
344 | { | |
345 | /* ZA is not supported. */ | |
346 | return false; | |
347 | } | |
348 | ||
349 | /* If the size is the correct one already, don't update it. If we do | |
350 | update the streaming vector length, we will invalidate the register | |
351 | state for ZA, and we do not want that. */ | |
352 | if (header.vl == sve_vl_from_vq (vq)) | |
353 | return true; | |
354 | ||
355 | /* The streaming vector length is about to get updated. Set the new value | |
356 | in the NT_ARM_ZA header and adjust the size as well. */ | |
357 | ||
358 | header.vl = sve_vl_from_vq (vq); | |
359 | header.size = sizeof (struct user_za_header); | |
360 | ||
361 | /* Update the NT_ARM_ZA register set with the new streaming vector | |
362 | length. */ | |
363 | iovec.iov_len = sizeof (header); | |
364 | iovec.iov_base = &header; | |
365 | ||
366 | if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_ZA, &iovec) < 0) | |
367 | { | |
368 | /* Streaming vector length change failed. */ | |
369 | return false; | |
370 | } | |
371 | ||
372 | /* At this point we have successfully adjusted the streaming vector length | |
373 | for the NT_ARM_ZA register set, and it should have no payload | |
374 | (no ZA state). */ | |
375 | ||
376 | return true; | |
377 | } | |
378 | ||
379 | /* See nat/aarch64-scalable-linux-ptrace.h. */ | |
380 | ||
381 | bool | |
382 | aarch64_za_set_svq (int tid, const struct reg_buffer_common *reg_buf, | |
383 | int svg_regnum) | |
384 | { | |
385 | uint64_t reg_svg = 0; | |
386 | ||
387 | /* The svg register may not be valid if we've not collected any value yet. | |
388 | This can happen, for example, if we're restoring the regcache after an | |
389 | inferior function call, and the svg register comes after the Z | |
390 | registers. */ | |
391 | if (reg_buf->get_register_status (svg_regnum) != REG_VALID) | |
392 | { | |
393 | /* If svg is not available yet, fetch it from ptrace. The svg value from | |
394 | ptrace is likely the correct one. */ | |
395 | uint64_t svq = aarch64_za_get_svq (tid); | |
396 | ||
397 | /* If something went wrong, just bail out. */ | |
398 | if (svq == 0) | |
399 | return false; | |
400 | ||
401 | reg_svg = sve_vg_from_vq (svq); | |
402 | } | |
403 | else | |
404 | reg_buf->raw_collect (svg_regnum, ®_svg); | |
405 | ||
406 | return aarch64_za_set_svq (tid, sve_vq_from_vg (reg_svg)); | |
407 | } | |
408 | ||
409 | /* See nat/aarch64-scalable-linux-ptrace.h. */ | |
410 | ||
78d6a7e9 LM |
411 | gdb::byte_vector |
412 | aarch64_fetch_sve_regset (int tid) | |
e9902bfc | 413 | { |
e9902bfc AH |
414 | uint64_t vq = aarch64_sve_get_vq (tid); |
415 | ||
416 | if (vq == 0) | |
ca65640f | 417 | perror_with_name (_("Unable to fetch SVE/SSVE vector length")); |
e9902bfc AH |
418 | |
419 | /* A ptrace call with NT_ARM_SVE will return a header followed by either a | |
420 | dump of all the SVE and FP registers, or an fpsimd structure (identical to | |
421 | the one returned by NT_FPREGSET) if the kernel has not yet executed any | |
422 | SVE code. Make sure we allocate enough space for a full SVE dump. */ | |
423 | ||
78d6a7e9 LM |
424 | gdb::byte_vector sve_state (SVE_PT_SIZE (vq, SVE_PT_REGS_SVE), 0); |
425 | ||
426 | struct iovec iovec; | |
427 | iovec.iov_base = sve_state.data (); | |
428 | iovec.iov_len = sve_state.size (); | |
e9902bfc | 429 | |
ca65640f LM |
430 | bool has_sve_state = !aarch64_has_ssve_state (tid); |
431 | if (ptrace (PTRACE_GETREGSET, tid, has_sve_state? NT_ARM_SVE : NT_ARM_SSVE, | |
432 | &iovec) < 0) | |
433 | perror_with_name (_("Unable to fetch SVE/SSVE registers")); | |
e9902bfc | 434 | |
78d6a7e9 LM |
435 | return sve_state; |
436 | } | |
437 | ||
438 | /* See nat/aarch64-scalable-linux-ptrace.h. */ | |
439 | ||
440 | void | |
441 | aarch64_store_sve_regset (int tid, const gdb::byte_vector &sve_state) | |
442 | { | |
443 | struct iovec iovec; | |
444 | /* We need to cast from (const void *) here. */ | |
445 | iovec.iov_base = (void *) sve_state.data (); | |
446 | iovec.iov_len = sve_state.size (); | |
447 | ||
ca65640f LM |
448 | bool has_sve_state = !aarch64_has_ssve_state (tid); |
449 | if (ptrace (PTRACE_SETREGSET, tid, has_sve_state? NT_ARM_SVE : NT_ARM_SSVE, | |
450 | &iovec) < 0) | |
451 | perror_with_name (_("Unable to store SVE/SSVE registers")); | |
452 | } | |
453 | ||
454 | /* See nat/aarch64-scalable-linux-ptrace.h. */ | |
455 | ||
456 | gdb::byte_vector | |
457 | aarch64_fetch_za_regset (int tid) | |
458 | { | |
459 | struct user_za_header header; | |
460 | if (!read_za_header (tid, header)) | |
461 | error (_("Failed to read NT_ARM_ZA header.")); | |
462 | ||
463 | if (!aarch64_sme_vl_valid (header.vl)) | |
464 | error (_("Found invalid vector length for NT_ARM_ZA.")); | |
465 | ||
466 | struct iovec iovec; | |
467 | iovec.iov_len = header.size; | |
468 | gdb::byte_vector za_state (header.size); | |
469 | iovec.iov_base = za_state.data (); | |
470 | ||
471 | if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_ZA, &iovec) < 0) | |
472 | perror_with_name (_("Failed to fetch NT_ARM_ZA register set.")); | |
473 | ||
474 | return za_state; | |
475 | } | |
476 | ||
477 | /* See nat/aarch64-scalable-linux-ptrace.h. */ | |
478 | ||
479 | void | |
480 | aarch64_store_za_regset (int tid, const gdb::byte_vector &za_state) | |
481 | { | |
482 | struct iovec iovec; | |
483 | /* We need to cast from (const void *) here. */ | |
484 | iovec.iov_base = (void *) za_state.data (); | |
485 | iovec.iov_len = za_state.size (); | |
486 | ||
487 | if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_ZA, &iovec) < 0) | |
488 | perror_with_name (_("Failed to write to the NT_ARM_ZA register set.")); | |
489 | } | |
490 | ||
491 | /* See nat/aarch64-scalable-linux-ptrace.h. */ | |
492 | ||
493 | void | |
494 | aarch64_initialize_za_regset (int tid) | |
495 | { | |
496 | /* First fetch the NT_ARM_ZA header so we can fetch the streaming vector | |
497 | length. */ | |
498 | struct user_za_header header; | |
499 | if (!read_za_header (tid, header)) | |
500 | error (_("Failed to read NT_ARM_ZA header.")); | |
501 | ||
502 | /* The vector should be default-initialized to zero, and we should account | |
503 | for the payload as well. */ | |
504 | std::vector<gdb_byte> za_new_state (ZA_PT_SIZE (sve_vq_from_vl (header.vl))); | |
505 | ||
506 | /* Adjust the header size since we are adding the initialized ZA | |
507 | payload. */ | |
508 | header.size = ZA_PT_SIZE (sve_vq_from_vl (header.vl)); | |
509 | ||
510 | /* Overlay the modified header onto the new ZA state. */ | |
511 | const gdb_byte *base = (gdb_byte *) &header; | |
512 | memcpy (za_new_state.data (), base, sizeof (user_za_header)); | |
513 | ||
514 | /* Set the ptrace request up and update the NT_ARM_ZA register set. */ | |
515 | struct iovec iovec; | |
516 | iovec.iov_len = za_new_state.size (); | |
517 | iovec.iov_base = za_new_state.data (); | |
518 | ||
519 | if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_ZA, &iovec) < 0) | |
520 | perror_with_name (_("Failed to initialize the NT_ARM_ZA register set.")); | |
521 | ||
42019af6 LM |
522 | if (supports_zt_registers (tid)) |
523 | { | |
524 | /* If this target supports SME2, upon initializing ZA, we also need to | |
525 | initialize the ZT registers with 0 values. Do so now. */ | |
526 | gdb::byte_vector zt_new_state (AARCH64_SME2_ZT0_SIZE, 0); | |
527 | aarch64_store_zt_regset (tid, zt_new_state); | |
528 | } | |
529 | ||
ca65640f LM |
530 | /* The NT_ARM_ZA register set should now contain a zero-initialized ZA |
531 | payload. */ | |
e9902bfc AH |
532 | } |
533 | ||
42019af6 LM |
534 | /* See nat/aarch64-scalable-linux-ptrace.h. */ |
535 | ||
536 | gdb::byte_vector | |
537 | aarch64_fetch_zt_regset (int tid) | |
538 | { | |
539 | /* Read NT_ARM_ZT. This register set is only available if | |
540 | the ZA bit is non-zero. */ | |
541 | gdb::byte_vector zt_state (AARCH64_SME2_ZT0_SIZE); | |
542 | ||
543 | struct iovec iovec; | |
544 | iovec.iov_len = AARCH64_SME2_ZT0_SIZE; | |
545 | iovec.iov_base = zt_state.data (); | |
546 | ||
547 | if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_ZT, &iovec) < 0) | |
548 | perror_with_name (_("Failed to fetch NT_ARM_ZT register set.")); | |
549 | ||
550 | return zt_state; | |
551 | } | |
552 | ||
553 | /* See nat/aarch64-scalable-linux-ptrace.h. */ | |
554 | ||
555 | void | |
556 | aarch64_store_zt_regset (int tid, const gdb::byte_vector &zt_state) | |
557 | { | |
558 | gdb_assert (zt_state.size () == AARCH64_SME2_ZT0_SIZE | |
559 | || zt_state.size () == 0); | |
560 | ||
561 | /* We need to be mindful of writing data to NT_ARM_ZT. If the ZA bit | |
562 | is 0 and we write something to ZT, it will flip the ZA bit. | |
563 | ||
564 | Right now this is taken care of by callers of this function. */ | |
565 | struct iovec iovec; | |
566 | iovec.iov_len = zt_state.size (); | |
567 | iovec.iov_base = (void *) zt_state.data (); | |
568 | ||
569 | /* Write the contents of ZT_STATE to the NT_ARM_ZT register set. */ | |
570 | if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_ZT, &iovec) < 0) | |
571 | perror_with_name (_("Failed to write to the NT_ARM_ZT register set.")); | |
572 | } | |
573 | ||
574 | /* See nat/aarch64-scalable-linux-ptrace.h. */ | |
575 | ||
576 | bool | |
577 | supports_zt_registers (int tid) | |
578 | { | |
579 | gdb_byte zt_state[AARCH64_SME2_ZT0_SIZE]; | |
580 | ||
581 | struct iovec iovec; | |
582 | iovec.iov_len = AARCH64_SME2_ZT0_SIZE; | |
583 | iovec.iov_base = (void *) zt_state; | |
584 | ||
585 | if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_ZT, &iovec) < 0) | |
586 | return false; | |
587 | ||
588 | return true; | |
589 | } | |
590 | ||
6afcd2d4 LM |
591 | /* If we are running in BE mode, byteswap the contents |
592 | of SRC to DST for SIZE bytes. Other, just copy the contents | |
593 | from SRC to DST. */ | |
594 | ||
595 | static void | |
596 | aarch64_maybe_swab128 (gdb_byte *dst, const gdb_byte *src, size_t size) | |
597 | { | |
598 | gdb_assert (src != nullptr && dst != nullptr); | |
599 | gdb_assert (size > 1); | |
600 | ||
601 | #if (__BYTE_ORDER == __BIG_ENDIAN) | |
602 | for (int i = 0; i < size - 1; i++) | |
603 | dst[i] = src[size - i]; | |
604 | #else | |
605 | memcpy (dst, src, size); | |
606 | #endif | |
607 | } | |
608 | ||
6ada909e | 609 | /* See nat/aarch64-scalable-linux-ptrace.h. */ |
e9902bfc AH |
610 | |
611 | void | |
78d6a7e9 | 612 | aarch64_sve_regs_copy_to_reg_buf (int tid, struct reg_buffer_common *reg_buf) |
e9902bfc | 613 | { |
78d6a7e9 LM |
614 | gdb::byte_vector sve_state = aarch64_fetch_sve_regset (tid); |
615 | ||
51e6b8cf | 616 | gdb_byte *base = sve_state.data (); |
78d6a7e9 LM |
617 | struct user_sve_header *header |
618 | = (struct user_sve_header *) sve_state.data (); | |
e9902bfc | 619 | |
48574d91 AH |
620 | uint64_t vq = sve_vq_from_vl (header->vl); |
621 | uint64_t vg = sve_vg_from_vl (header->vl); | |
e9902bfc AH |
622 | |
623 | /* Sanity check the data in the header. */ | |
624 | if (!sve_vl_valid (header->vl) | |
625 | || SVE_PT_SIZE (vq, header->flags) != header->size) | |
626 | error (_("Invalid SVE header from kernel.")); | |
627 | ||
48574d91 AH |
628 | /* Update VG. Note, the registers in the regcache will already be of the |
629 | correct length. */ | |
630 | reg_buf->raw_supply (AARCH64_SVE_VG_REGNUM, &vg); | |
e9902bfc AH |
631 | |
632 | if (HAS_SVE_STATE (*header)) | |
633 | { | |
634 | /* The register dump contains a set of SVE registers. */ | |
635 | ||
636 | for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++) | |
637 | reg_buf->raw_supply (AARCH64_SVE_Z0_REGNUM + i, | |
638 | base + SVE_PT_SVE_ZREG_OFFSET (vq, i)); | |
639 | ||
640 | for (int i = 0; i < AARCH64_SVE_P_REGS_NUM; i++) | |
641 | reg_buf->raw_supply (AARCH64_SVE_P0_REGNUM + i, | |
642 | base + SVE_PT_SVE_PREG_OFFSET (vq, i)); | |
643 | ||
644 | reg_buf->raw_supply (AARCH64_SVE_FFR_REGNUM, | |
645 | base + SVE_PT_SVE_FFR_OFFSET (vq)); | |
646 | reg_buf->raw_supply (AARCH64_FPSR_REGNUM, | |
647 | base + SVE_PT_SVE_FPSR_OFFSET (vq)); | |
648 | reg_buf->raw_supply (AARCH64_FPCR_REGNUM, | |
649 | base + SVE_PT_SVE_FPCR_OFFSET (vq)); | |
650 | } | |
651 | else | |
652 | { | |
6afcd2d4 LM |
653 | /* WARNING: SIMD state is laid out in memory in target-endian format, |
654 | while SVE state is laid out in an endianness-independent format (LE). | |
655 | ||
656 | So we have a couple cases to consider: | |
657 | ||
658 | 1 - If the target is big endian, then SIMD state is big endian, | |
659 | requiring a byteswap. | |
660 | ||
661 | 2 - If the target is little endian, then SIMD state is little endian, | |
662 | which matches the SVE format, so no byteswap is needed. */ | |
663 | ||
e9902bfc AH |
664 | /* There is no SVE state yet - the register dump contains a fpsimd |
665 | structure instead. These registers still exist in the hardware, but | |
666 | the kernel has not yet initialised them, and so they will be null. */ | |
667 | ||
6afcd2d4 | 668 | gdb_byte *reg = (gdb_byte *) alloca (SVE_PT_SVE_ZREG_SIZE (vq)); |
e9902bfc AH |
669 | struct user_fpsimd_state *fpsimd |
670 | = (struct user_fpsimd_state *)(base + SVE_PT_FPSIMD_OFFSET); | |
671 | ||
6afcd2d4 LM |
672 | /* Make sure we have a zeroed register buffer. We will need the zero |
673 | padding below. */ | |
674 | memset (reg, 0, SVE_PT_SVE_ZREG_SIZE (vq)); | |
675 | ||
e9902bfc AH |
676 | /* Copy across the V registers from fpsimd structure to the Z registers, |
677 | ensuring the non overlapping state is set to null. */ | |
678 | ||
e9902bfc AH |
679 | for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++) |
680 | { | |
6afcd2d4 LM |
681 | /* Handle big endian/little endian SIMD/SVE conversion. */ |
682 | aarch64_maybe_swab128 (reg, (const gdb_byte *) &fpsimd->vregs[i], | |
683 | V_REGISTER_SIZE); | |
684 | reg_buf->raw_supply (AARCH64_SVE_Z0_REGNUM + i, reg); | |
e9902bfc AH |
685 | } |
686 | ||
51e6b8cf SM |
687 | reg_buf->raw_supply (AARCH64_FPSR_REGNUM, |
688 | (const gdb_byte *) &fpsimd->fpsr); | |
689 | reg_buf->raw_supply (AARCH64_FPCR_REGNUM, | |
690 | (const gdb_byte *) &fpsimd->fpcr); | |
e9902bfc AH |
691 | |
692 | /* Clear the SVE only registers. */ | |
6afcd2d4 | 693 | memset (reg, 0, SVE_PT_SVE_ZREG_SIZE (vq)); |
e9902bfc AH |
694 | |
695 | for (int i = 0; i < AARCH64_SVE_P_REGS_NUM; i++) | |
6afcd2d4 | 696 | reg_buf->raw_supply (AARCH64_SVE_P0_REGNUM + i, reg); |
e9902bfc | 697 | |
6afcd2d4 | 698 | reg_buf->raw_supply (AARCH64_SVE_FFR_REGNUM, reg); |
e9902bfc | 699 | } |
78d6a7e9 LM |
700 | |
701 | /* At this point we have updated the register cache with the contents of | |
702 | the NT_ARM_SVE register set. */ | |
e9902bfc AH |
703 | } |
704 | ||
6ada909e | 705 | /* See nat/aarch64-scalable-linux-ptrace.h. */ |
e9902bfc AH |
706 | |
707 | void | |
78d6a7e9 LM |
708 | aarch64_sve_regs_copy_from_reg_buf (int tid, |
709 | struct reg_buffer_common *reg_buf) | |
e9902bfc | 710 | { |
78d6a7e9 LM |
711 | /* First store the vector length to the thread. This is done first to |
712 | ensure the ptrace buffers read from the kernel are the correct size. */ | |
713 | if (!aarch64_sve_set_vq (tid, reg_buf)) | |
714 | perror_with_name (_("Unable to set VG register")); | |
715 | ||
716 | /* Obtain a dump of SVE registers from ptrace. */ | |
717 | gdb::byte_vector sve_state = aarch64_fetch_sve_regset (tid); | |
718 | ||
719 | struct user_sve_header *header = (struct user_sve_header *) sve_state.data (); | |
48574d91 | 720 | uint64_t vq = sve_vq_from_vl (header->vl); |
e9902bfc | 721 | |
78d6a7e9 LM |
722 | gdb::byte_vector new_state (SVE_PT_SIZE (32, SVE_PT_REGS_SVE), 0); |
723 | memcpy (new_state.data (), sve_state.data (), sve_state.size ()); | |
724 | header = (struct user_sve_header *) new_state.data (); | |
51e6b8cf | 725 | gdb_byte *base = new_state.data (); |
78d6a7e9 | 726 | |
e9902bfc AH |
727 | /* Sanity check the data in the header. */ |
728 | if (!sve_vl_valid (header->vl) | |
729 | || SVE_PT_SIZE (vq, header->flags) != header->size) | |
730 | error (_("Invalid SVE header from kernel.")); | |
731 | ||
e9902bfc AH |
732 | if (!HAS_SVE_STATE (*header)) |
733 | { | |
734 | /* There is no SVE state yet - the register dump contains a fpsimd | |
735 | structure instead. Where possible we want to write the reg_buf data | |
736 | back to the kernel using the fpsimd structure. However, if we cannot | |
737 | then we'll need to reformat the fpsimd into a full SVE structure, | |
738 | resulting in the initialization of SVE state written back to the | |
739 | kernel, which is why we try to avoid it. */ | |
740 | ||
78d6a7e9 LM |
741 | /* Buffer (using the maximum size a Z register) used to look for zeroed |
742 | out sve state. */ | |
743 | gdb_byte reg[256]; | |
744 | memset (reg, 0, sizeof (reg)); | |
e9902bfc AH |
745 | |
746 | /* Check in the reg_buf if any of the Z registers are set after the | |
747 | first 128 bits, or if any of the other SVE registers are set. */ | |
78d6a7e9 | 748 | bool has_sve_state = false; |
e9902bfc AH |
749 | for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++) |
750 | { | |
78d6a7e9 LM |
751 | if (!reg_buf->raw_compare (AARCH64_SVE_Z0_REGNUM + i, reg, |
752 | V_REGISTER_SIZE)) | |
753 | { | |
754 | has_sve_state = true; | |
755 | break; | |
756 | } | |
e9902bfc AH |
757 | } |
758 | ||
759 | if (!has_sve_state) | |
760 | for (int i = 0; i < AARCH64_SVE_P_REGS_NUM; i++) | |
761 | { | |
78d6a7e9 LM |
762 | if (!reg_buf->raw_compare (AARCH64_SVE_P0_REGNUM + i, reg, 0)) |
763 | { | |
764 | has_sve_state = true; | |
765 | break; | |
766 | } | |
e9902bfc AH |
767 | } |
768 | ||
769 | if (!has_sve_state) | |
78d6a7e9 LM |
770 | has_sve_state |
771 | = !reg_buf->raw_compare (AARCH64_SVE_FFR_REGNUM, reg, 0); | |
772 | ||
773 | struct user_fpsimd_state *fpsimd | |
774 | = (struct user_fpsimd_state *)(base + SVE_PT_FPSIMD_OFFSET); | |
e9902bfc AH |
775 | |
776 | /* If no SVE state exists, then use the existing fpsimd structure to | |
777 | write out state and return. */ | |
778 | if (!has_sve_state) | |
779 | { | |
6afcd2d4 LM |
780 | /* WARNING: SIMD state is laid out in memory in target-endian format, |
781 | while SVE state is laid out in an endianness-independent format | |
782 | (LE). | |
783 | ||
784 | So we have a couple cases to consider: | |
785 | ||
786 | 1 - If the target is big endian, then SIMD state is big endian, | |
787 | requiring a byteswap. | |
788 | ||
789 | 2 - If the target is little endian, then SIMD state is little | |
790 | endian, which matches the SVE format, so no byteswap is needed. */ | |
791 | ||
e9902bfc AH |
792 | /* The collects of the Z registers will overflow the size of a vreg. |
793 | There is enough space in the structure to allow for this, but we | |
794 | cannot overflow into the next register as we might not be | |
795 | collecting every register. */ | |
796 | ||
797 | for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++) | |
798 | { | |
799 | if (REG_VALID | |
800 | == reg_buf->get_register_status (AARCH64_SVE_Z0_REGNUM + i)) | |
801 | { | |
6afcd2d4 LM |
802 | reg_buf->raw_collect (AARCH64_SVE_Z0_REGNUM + i, reg); |
803 | /* Handle big endian/little endian SIMD/SVE conversion. */ | |
804 | aarch64_maybe_swab128 ((gdb_byte *) &fpsimd->vregs[i], reg, | |
805 | V_REGISTER_SIZE); | |
e9902bfc AH |
806 | } |
807 | } | |
808 | ||
809 | if (REG_VALID == reg_buf->get_register_status (AARCH64_FPSR_REGNUM)) | |
51e6b8cf SM |
810 | reg_buf->raw_collect (AARCH64_FPSR_REGNUM, |
811 | (gdb_byte *) &fpsimd->fpsr); | |
e9902bfc | 812 | if (REG_VALID == reg_buf->get_register_status (AARCH64_FPCR_REGNUM)) |
51e6b8cf SM |
813 | reg_buf->raw_collect (AARCH64_FPCR_REGNUM, |
814 | (gdb_byte *) &fpsimd->fpcr); | |
e9902bfc | 815 | |
78d6a7e9 LM |
816 | /* At this point we have collected all the data from the register |
817 | cache and we are ready to update the FPSIMD register content | |
818 | of the thread. */ | |
e9902bfc | 819 | |
78d6a7e9 LM |
820 | /* Fall through so we can update the thread's contents with the |
821 | FPSIMD register cache values. */ | |
822 | } | |
823 | else | |
824 | { | |
825 | /* Otherwise, reformat the fpsimd structure into a full SVE set, by | |
826 | expanding the V registers (working backwards so we don't splat | |
827 | registers before they are copied) and using zero for everything | |
828 | else. | |
829 | Note that enough space for a full SVE dump was originally allocated | |
830 | for base. */ | |
831 | ||
832 | header->flags |= SVE_PT_REGS_SVE; | |
833 | header->size = SVE_PT_SIZE (vq, SVE_PT_REGS_SVE); | |
834 | ||
835 | memcpy (base + SVE_PT_SVE_FPSR_OFFSET (vq), &fpsimd->fpsr, | |
836 | sizeof (uint32_t)); | |
837 | memcpy (base + SVE_PT_SVE_FPCR_OFFSET (vq), &fpsimd->fpcr, | |
838 | sizeof (uint32_t)); | |
839 | ||
840 | for (int i = AARCH64_SVE_Z_REGS_NUM - 1; i >= 0 ; i--) | |
841 | { | |
842 | memcpy (base + SVE_PT_SVE_ZREG_OFFSET (vq, i), &fpsimd->vregs[i], | |
843 | sizeof (__int128_t)); | |
844 | } | |
e9902bfc | 845 | |
78d6a7e9 LM |
846 | /* At this point we have converted the FPSIMD layout to an SVE |
847 | layout and copied the register data. | |
e9902bfc | 848 | |
78d6a7e9 LM |
849 | Fall through so we can update the thread's contents with the SVE |
850 | register cache values. */ | |
e9902bfc AH |
851 | } |
852 | } | |
78d6a7e9 LM |
853 | else |
854 | { | |
855 | /* We already have SVE state for this thread, so we just need to update | |
856 | the values of the registers. */ | |
857 | for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++) | |
858 | if (REG_VALID == reg_buf->get_register_status (AARCH64_SVE_Z0_REGNUM | |
859 | + i)) | |
860 | reg_buf->raw_collect (AARCH64_SVE_Z0_REGNUM + i, | |
861 | base + SVE_PT_SVE_ZREG_OFFSET (vq, i)); | |
e9902bfc | 862 | |
78d6a7e9 LM |
863 | for (int i = 0; i < AARCH64_SVE_P_REGS_NUM; i++) |
864 | if (REG_VALID == reg_buf->get_register_status (AARCH64_SVE_P0_REGNUM | |
865 | + i)) | |
866 | reg_buf->raw_collect (AARCH64_SVE_P0_REGNUM + i, | |
867 | base + SVE_PT_SVE_PREG_OFFSET (vq, i)); | |
868 | ||
869 | if (REG_VALID == reg_buf->get_register_status (AARCH64_SVE_FFR_REGNUM)) | |
870 | reg_buf->raw_collect (AARCH64_SVE_FFR_REGNUM, | |
871 | base + SVE_PT_SVE_FFR_OFFSET (vq)); | |
872 | if (REG_VALID == reg_buf->get_register_status (AARCH64_FPSR_REGNUM)) | |
873 | reg_buf->raw_collect (AARCH64_FPSR_REGNUM, | |
874 | base + SVE_PT_SVE_FPSR_OFFSET (vq)); | |
875 | if (REG_VALID == reg_buf->get_register_status (AARCH64_FPCR_REGNUM)) | |
876 | reg_buf->raw_collect (AARCH64_FPCR_REGNUM, | |
877 | base + SVE_PT_SVE_FPCR_OFFSET (vq)); | |
878 | } | |
e9902bfc | 879 | |
78d6a7e9 LM |
880 | /* At this point we have collected all the data from the register cache and |
881 | we are ready to update the SVE/FPSIMD register contents of the thread. | |
e9902bfc | 882 | |
78d6a7e9 LM |
883 | sve_state should contain all the data in the correct format, ready to be |
884 | passed on to ptrace. */ | |
885 | aarch64_store_sve_regset (tid, new_state); | |
e9902bfc | 886 | } |
ca65640f LM |
887 | |
888 | /* See nat/aarch64-scalable-linux-ptrace.h. */ | |
889 | ||
890 | void | |
891 | aarch64_za_regs_copy_to_reg_buf (int tid, struct reg_buffer_common *reg_buf, | |
892 | int za_regnum, int svg_regnum, | |
893 | int svcr_regnum) | |
894 | { | |
895 | /* Fetch the current ZA state from the thread. */ | |
896 | gdb::byte_vector za_state = aarch64_fetch_za_regset (tid); | |
897 | ||
898 | /* Sanity check. */ | |
899 | gdb_assert (!za_state.empty ()); | |
900 | ||
51e6b8cf | 901 | gdb_byte *base = za_state.data (); |
ca65640f LM |
902 | struct user_za_header *header = (struct user_za_header *) base; |
903 | ||
904 | /* If we have ZA state, read it. Otherwise, make the contents of ZA | |
905 | in the register cache all zeroes. This is how we present the ZA | |
906 | state when it is not initialized. */ | |
907 | uint64_t svcr_value = 0; | |
908 | if (aarch64_has_za_state (tid)) | |
909 | { | |
910 | /* Sanity check the data in the header. */ | |
911 | if (!sve_vl_valid (header->vl) | |
912 | || ZA_PT_SIZE (sve_vq_from_vl (header->vl)) != header->size) | |
913 | { | |
914 | error (_("Found invalid streaming vector length in NT_ARM_ZA" | |
915 | " register set")); | |
916 | } | |
917 | ||
918 | reg_buf->raw_supply (za_regnum, base + ZA_PT_ZA_OFFSET); | |
919 | svcr_value |= SVCR_ZA_BIT; | |
920 | } | |
921 | else | |
922 | { | |
923 | size_t za_bytes = header->vl * header->vl; | |
924 | gdb_byte za_zeroed[za_bytes]; | |
925 | memset (za_zeroed, 0, za_bytes); | |
926 | reg_buf->raw_supply (za_regnum, za_zeroed); | |
927 | } | |
928 | ||
929 | /* Handle the svg and svcr registers separately. We need to calculate | |
930 | their values manually, as the Linux Kernel doesn't expose those | |
931 | explicitly. */ | |
932 | svcr_value |= aarch64_has_ssve_state (tid)? SVCR_SM_BIT : 0; | |
933 | uint64_t svg_value = sve_vg_from_vl (header->vl); | |
934 | ||
935 | /* Update the contents of svg and svcr registers. */ | |
936 | reg_buf->raw_supply (svg_regnum, &svg_value); | |
937 | reg_buf->raw_supply (svcr_regnum, &svcr_value); | |
938 | ||
939 | /* The register buffer should now contain the updated copy of the NT_ARM_ZA | |
940 | state. */ | |
941 | } | |
942 | ||
943 | /* See nat/aarch64-scalable-linux-ptrace.h. */ | |
944 | ||
945 | void | |
946 | aarch64_za_regs_copy_from_reg_buf (int tid, | |
947 | struct reg_buffer_common *reg_buf, | |
948 | int za_regnum, int svg_regnum, | |
949 | int svcr_regnum) | |
950 | { | |
951 | /* REG_BUF contains the updated ZA state. We need to extract that state | |
952 | and write it to the thread TID. */ | |
953 | ||
954 | ||
955 | /* First check if there is a change to the streaming vector length. Two | |
956 | outcomes are possible here: | |
957 | ||
958 | 1 - The streaming vector length in the register cache differs from the | |
959 | one currently on the thread state. This means that we will need to | |
960 | update the NT_ARM_ZA register set to reflect the new streaming vector | |
961 | length. | |
962 | ||
963 | 2 - The streaming vector length in the register cache is the same as in | |
964 | the thread state. This means we do not need to update the NT_ARM_ZA | |
965 | register set for a new streaming vector length, and we only need to | |
966 | deal with changes to za, svg and svcr. | |
967 | ||
968 | None of the two possibilities above imply that the ZA state actually | |
969 | exists. They only determine what needs to be done with any ZA content | |
970 | based on the state of the streaming vector length. */ | |
971 | ||
972 | /* First fetch the NT_ARM_ZA header so we can fetch the streaming vector | |
973 | length. */ | |
974 | struct user_za_header header; | |
975 | if (!read_za_header (tid, header)) | |
976 | error (_("Failed to read NT_ARM_ZA header.")); | |
977 | ||
978 | /* Fetch the current streaming vector length. */ | |
979 | uint64_t old_svg = sve_vg_from_vl (header.vl); | |
980 | ||
981 | /* Fetch the (potentially) new streaming vector length. */ | |
982 | uint64_t new_svg; | |
983 | reg_buf->raw_collect (svg_regnum, &new_svg); | |
984 | ||
985 | /* Did the streaming vector length change? */ | |
986 | bool svg_changed = new_svg != old_svg; | |
987 | ||
988 | /* First store the streaming vector length to the thread. This is done | |
989 | first to ensure the ptrace buffers read from the kernel are the correct | |
990 | size. If the streaming vector length is the same as the current one, it | |
991 | won't be updated. */ | |
992 | if (!aarch64_za_set_svq (tid, reg_buf, svg_regnum)) | |
993 | error (_("Unable to set svg register")); | |
994 | ||
995 | bool has_za_state = aarch64_has_za_state (tid); | |
996 | ||
997 | size_t za_bytes = sve_vl_from_vg (old_svg) * sve_vl_from_vg (old_svg); | |
998 | gdb_byte za_zeroed[za_bytes]; | |
999 | memset (za_zeroed, 0, za_bytes); | |
1000 | ||
1001 | /* If the streaming vector length changed, zero out the contents of ZA in | |
1002 | the register cache. Otherwise, we will need to update the ZA contents | |
1003 | in the thread with the ZA contents from the register cache, and they will | |
1004 | differ in size. */ | |
1005 | if (svg_changed) | |
1006 | reg_buf->raw_supply (za_regnum, za_zeroed); | |
1007 | ||
1008 | /* When we update svg, we don't automatically initialize the ZA buffer. If | |
1009 | we have no ZA state and the ZA register contents in the register cache are | |
1010 | zero, just return and leave the ZA register cache contents as zero. */ | |
1011 | if (!has_za_state | |
1012 | && reg_buf->raw_compare (za_regnum, za_zeroed, 0)) | |
1013 | { | |
1014 | /* No ZA state in the thread or in the register cache. This was likely | |
1015 | just an adjustment of the streaming vector length. Let this fall | |
1016 | through and update svcr and svg in the register cache. */ | |
1017 | } | |
1018 | else | |
1019 | { | |
1020 | /* If there is no ZA state but the register cache contains ZA data, we | |
1021 | need to initialize the ZA data through ptrace. First we initialize | |
1022 | all the bytes of ZA to zero. */ | |
1023 | if (!has_za_state | |
1024 | && !reg_buf->raw_compare (za_regnum, za_zeroed, 0)) | |
1025 | aarch64_initialize_za_regset (tid); | |
1026 | ||
1027 | /* From this point onwards, it is assumed we have a ZA payload in | |
1028 | the NT_ARM_ZA register set for this thread, and we need to update | |
1029 | such state based on the contents of the register cache. */ | |
1030 | ||
1031 | /* Fetch the current ZA state from the thread. */ | |
1032 | gdb::byte_vector za_state = aarch64_fetch_za_regset (tid); | |
1033 | ||
51e6b8cf | 1034 | gdb_byte *base = za_state.data (); |
ca65640f LM |
1035 | struct user_za_header *za_header = (struct user_za_header *) base; |
1036 | uint64_t svq = sve_vq_from_vl (za_header->vl); | |
1037 | ||
1038 | /* Sanity check the data in the header. */ | |
1039 | if (!sve_vl_valid (za_header->vl) | |
1040 | || ZA_PT_SIZE (svq) != za_header->size) | |
1041 | error (_("Invalid vector length or payload size when reading ZA.")); | |
1042 | ||
1043 | /* Overwrite the ZA state contained in the thread with the ZA state from | |
1044 | the register cache. */ | |
1045 | if (REG_VALID == reg_buf->get_register_status (za_regnum)) | |
1046 | reg_buf->raw_collect (za_regnum, base + ZA_PT_ZA_OFFSET); | |
1047 | ||
1048 | /* Write back the ZA state to the thread's NT_ARM_ZA register set. */ | |
1049 | aarch64_store_za_regset (tid, za_state); | |
1050 | } | |
1051 | ||
1052 | /* Update svcr and svg accordingly. */ | |
1053 | uint64_t svcr_value = 0; | |
1054 | svcr_value |= aarch64_has_ssve_state (tid)? SVCR_SM_BIT : 0; | |
1055 | svcr_value |= aarch64_has_za_state (tid)? SVCR_ZA_BIT : 0; | |
1056 | reg_buf->raw_supply (svcr_regnum, &svcr_value); | |
1057 | ||
1058 | /* At this point we have written the data contained in the register cache to | |
1059 | the thread's NT_ARM_ZA register set. */ | |
1060 | } | |
42019af6 LM |
1061 | |
1062 | /* See nat/aarch64-scalable-linux-ptrace.h. */ | |
1063 | ||
1064 | void | |
1065 | aarch64_zt_regs_copy_to_reg_buf (int tid, struct reg_buffer_common *reg_buf, | |
1066 | int zt_regnum) | |
1067 | { | |
1068 | /* If we have ZA state, read the ZT state. Otherwise, make the contents of | |
1069 | ZT in the register cache all zeroes. This is how we present the ZT | |
1070 | state when it is not initialized (ZA not active). */ | |
1071 | if (aarch64_has_za_state (tid)) | |
1072 | { | |
1073 | /* Fetch the current ZT state from the thread. */ | |
1074 | gdb::byte_vector zt_state = aarch64_fetch_zt_regset (tid); | |
1075 | ||
1076 | /* Sanity check. */ | |
1077 | gdb_assert (!zt_state.empty ()); | |
1078 | ||
1079 | /* Copy the ZT data to the register buffer. */ | |
1080 | reg_buf->raw_supply (zt_regnum, zt_state.data ()); | |
1081 | } | |
1082 | else | |
1083 | { | |
1084 | /* Zero out ZT. */ | |
1085 | gdb::byte_vector zt_zeroed (AARCH64_SME2_ZT0_SIZE, 0); | |
1086 | reg_buf->raw_supply (zt_regnum, zt_zeroed.data ()); | |
1087 | } | |
1088 | ||
1089 | /* The register buffer should now contain the updated copy of the NT_ARM_ZT | |
1090 | state. */ | |
1091 | } | |
1092 | ||
1093 | /* See nat/aarch64-scalable-linux-ptrace.h. */ | |
1094 | ||
1095 | void | |
1096 | aarch64_zt_regs_copy_from_reg_buf (int tid, | |
1097 | struct reg_buffer_common *reg_buf, | |
1098 | int zt_regnum) | |
1099 | { | |
1100 | /* Do we have a valid ZA state? */ | |
1101 | bool valid_za = aarch64_has_za_state (tid); | |
1102 | ||
1103 | /* Is the register buffer contents for ZT all zeroes? */ | |
1104 | gdb::byte_vector zt_bytes (AARCH64_SME2_ZT0_SIZE, 0); | |
1105 | bool zt_is_all_zeroes | |
1106 | = reg_buf->raw_compare (zt_regnum, zt_bytes.data (), 0); | |
1107 | ||
1108 | /* If ZA state is valid or if we have non-zero data for ZT in the register | |
1109 | buffer, we will invoke ptrace to write the ZT state. Otherwise we don't | |
1110 | have to do anything here. */ | |
1111 | if (valid_za || !zt_is_all_zeroes) | |
1112 | { | |
1113 | if (!valid_za) | |
1114 | { | |
1115 | /* ZA state is not valid. That means we need to initialize the ZA | |
1116 | state prior to writing the ZT state. */ | |
1117 | aarch64_initialize_za_regset (tid); | |
1118 | } | |
1119 | ||
1120 | /* Extract the ZT data from the register buffer. */ | |
1121 | reg_buf->raw_collect (zt_regnum, zt_bytes.data ()); | |
1122 | ||
1123 | /* Write the ZT data to thread TID. */ | |
1124 | aarch64_store_zt_regset (tid, zt_bytes); | |
1125 | } | |
1126 | ||
1127 | /* At this point we have (potentially) written the data contained in the | |
1128 | register cache to the thread's NT_ARM_ZT register set. */ | |
1129 | } |