1 /* Common target dependent for AArch64 systems.
3 Copyright (C) 2018-2020 Free Software Foundation, Inc.
5 This file is part of GDB.
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.
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.
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/>. */
20 #include <sys/utsname.h>
22 #include "gdbsupport/common-defs.h"
23 #include "elf/external.h"
24 #include "elf/common.h"
25 #include "aarch64-sve-linux-ptrace.h"
26 #include "arch/aarch64.h"
27 #include "gdbsupport/common-regcache.h"
28 #include "gdbsupport/byte-vector.h"
30 /* See nat/aarch64-sve-linux-ptrace.h. */
33 aarch64_sve_get_vq (int tid
)
36 struct user_sve_header header
;
38 iovec
.iov_len
= sizeof (header
);
39 iovec
.iov_base
= &header
;
41 /* Ptrace gives the vector length in bytes. Convert it to VQ, the number of
42 128bit chunks in a Z register. We use VQ because 128bits is the minimum
43 a Z register can increase in size. */
45 if (ptrace (PTRACE_GETREGSET
, tid
, NT_ARM_SVE
, &iovec
) < 0)
47 /* SVE is not supported. */
51 uint64_t vq
= sve_vq_from_vl (header
.vl
);
53 if (!sve_vl_valid (header
.vl
))
55 warning (_("Invalid SVE state from kernel; SVE disabled."));
62 /* See nat/aarch64-sve-linux-ptrace.h. */
65 aarch64_sve_set_vq (int tid
, uint64_t vq
)
68 struct user_sve_header header
;
70 iovec
.iov_len
= sizeof (header
);
71 iovec
.iov_base
= &header
;
73 if (ptrace (PTRACE_GETREGSET
, tid
, NT_ARM_SVE
, &iovec
) < 0)
75 /* SVE is not supported. */
79 header
.vl
= sve_vl_from_vq (vq
);
81 if (ptrace (PTRACE_SETREGSET
, tid
, NT_ARM_SVE
, &iovec
) < 0)
83 /* Vector length change failed. */
90 /* See nat/aarch64-sve-linux-ptrace.h. */
93 aarch64_sve_set_vq (int tid
, struct reg_buffer_common
*reg_buf
)
97 /* The VG register may not be valid if we've not collected any value yet.
98 This can happen, for example, if we're restoring the regcache after an
99 inferior function call, and the VG register comes after the Z
101 if (reg_buf
->get_register_status (AARCH64_SVE_VG_REGNUM
) != REG_VALID
)
103 /* If vg is not available yet, fetch it from ptrace. The VG value from
104 ptrace is likely the correct one. */
105 uint64_t vq
= aarch64_sve_get_vq (tid
);
107 /* If something went wrong, just bail out. */
111 reg_vg
= sve_vg_from_vq (vq
);
114 reg_buf
->raw_collect (AARCH64_SVE_VG_REGNUM
, ®_vg
);
116 return aarch64_sve_set_vq (tid
, sve_vq_from_vg (reg_vg
));
119 /* See nat/aarch64-sve-linux-ptrace.h. */
121 std::unique_ptr
<gdb_byte
[]>
122 aarch64_sve_get_sveregs (int tid
)
125 uint64_t vq
= aarch64_sve_get_vq (tid
);
128 perror_with_name (_("Unable to fetch SVE register header"));
130 /* A ptrace call with NT_ARM_SVE will return a header followed by either a
131 dump of all the SVE and FP registers, or an fpsimd structure (identical to
132 the one returned by NT_FPREGSET) if the kernel has not yet executed any
133 SVE code. Make sure we allocate enough space for a full SVE dump. */
135 iovec
.iov_len
= SVE_PT_SIZE (vq
, SVE_PT_REGS_SVE
);
136 std::unique_ptr
<gdb_byte
[]> buf (new gdb_byte
[iovec
.iov_len
]);
137 iovec
.iov_base
= buf
.get ();
139 if (ptrace (PTRACE_GETREGSET
, tid
, NT_ARM_SVE
, &iovec
) < 0)
140 perror_with_name (_("Unable to fetch SVE registers"));
145 /* See nat/aarch64-sve-linux-ptrace.h. */
148 aarch64_sve_regs_copy_to_reg_buf (struct reg_buffer_common
*reg_buf
,
151 char *base
= (char *) buf
;
152 struct user_sve_header
*header
= (struct user_sve_header
*) buf
;
154 uint64_t vq
= sve_vq_from_vl (header
->vl
);
155 uint64_t vg
= sve_vg_from_vl (header
->vl
);
157 /* Sanity check the data in the header. */
158 if (!sve_vl_valid (header
->vl
)
159 || SVE_PT_SIZE (vq
, header
->flags
) != header
->size
)
160 error (_("Invalid SVE header from kernel."));
162 /* Update VG. Note, the registers in the regcache will already be of the
164 reg_buf
->raw_supply (AARCH64_SVE_VG_REGNUM
, &vg
);
166 if (HAS_SVE_STATE (*header
))
168 /* The register dump contains a set of SVE registers. */
170 for (int i
= 0; i
< AARCH64_SVE_Z_REGS_NUM
; i
++)
171 reg_buf
->raw_supply (AARCH64_SVE_Z0_REGNUM
+ i
,
172 base
+ SVE_PT_SVE_ZREG_OFFSET (vq
, i
));
174 for (int i
= 0; i
< AARCH64_SVE_P_REGS_NUM
; i
++)
175 reg_buf
->raw_supply (AARCH64_SVE_P0_REGNUM
+ i
,
176 base
+ SVE_PT_SVE_PREG_OFFSET (vq
, i
));
178 reg_buf
->raw_supply (AARCH64_SVE_FFR_REGNUM
,
179 base
+ SVE_PT_SVE_FFR_OFFSET (vq
));
180 reg_buf
->raw_supply (AARCH64_FPSR_REGNUM
,
181 base
+ SVE_PT_SVE_FPSR_OFFSET (vq
));
182 reg_buf
->raw_supply (AARCH64_FPCR_REGNUM
,
183 base
+ SVE_PT_SVE_FPCR_OFFSET (vq
));
187 /* There is no SVE state yet - the register dump contains a fpsimd
188 structure instead. These registers still exist in the hardware, but
189 the kernel has not yet initialised them, and so they will be null. */
191 char *zero_reg
= (char *) alloca (SVE_PT_SVE_ZREG_SIZE (vq
));
192 struct user_fpsimd_state
*fpsimd
193 = (struct user_fpsimd_state
*)(base
+ SVE_PT_FPSIMD_OFFSET
);
195 /* Copy across the V registers from fpsimd structure to the Z registers,
196 ensuring the non overlapping state is set to null. */
198 memset (zero_reg
, 0, SVE_PT_SVE_ZREG_SIZE (vq
));
200 for (int i
= 0; i
< AARCH64_SVE_Z_REGS_NUM
; i
++)
202 memcpy (zero_reg
, &fpsimd
->vregs
[i
], sizeof (__int128_t
));
203 reg_buf
->raw_supply (AARCH64_SVE_Z0_REGNUM
+ i
, zero_reg
);
206 reg_buf
->raw_supply (AARCH64_FPSR_REGNUM
, &fpsimd
->fpsr
);
207 reg_buf
->raw_supply (AARCH64_FPCR_REGNUM
, &fpsimd
->fpcr
);
209 /* Clear the SVE only registers. */
211 for (int i
= 0; i
< AARCH64_SVE_P_REGS_NUM
; i
++)
212 reg_buf
->raw_supply (AARCH64_SVE_P0_REGNUM
+ i
, zero_reg
);
214 reg_buf
->raw_supply (AARCH64_SVE_FFR_REGNUM
, zero_reg
);
218 /* See nat/aarch64-sve-linux-ptrace.h. */
221 aarch64_sve_regs_copy_from_reg_buf (const struct reg_buffer_common
*reg_buf
,
224 struct user_sve_header
*header
= (struct user_sve_header
*) buf
;
225 char *base
= (char *) buf
;
226 uint64_t vq
= sve_vq_from_vl (header
->vl
);
228 /* Sanity check the data in the header. */
229 if (!sve_vl_valid (header
->vl
)
230 || SVE_PT_SIZE (vq
, header
->flags
) != header
->size
)
231 error (_("Invalid SVE header from kernel."));
233 if (!HAS_SVE_STATE (*header
))
235 /* There is no SVE state yet - the register dump contains a fpsimd
236 structure instead. Where possible we want to write the reg_buf data
237 back to the kernel using the fpsimd structure. However, if we cannot
238 then we'll need to reformat the fpsimd into a full SVE structure,
239 resulting in the initialization of SVE state written back to the
240 kernel, which is why we try to avoid it. */
242 bool has_sve_state
= false;
243 char *zero_reg
= (char *) alloca (SVE_PT_SVE_ZREG_SIZE (vq
));
244 struct user_fpsimd_state
*fpsimd
245 = (struct user_fpsimd_state
*)(base
+ SVE_PT_FPSIMD_OFFSET
);
247 memset (zero_reg
, 0, SVE_PT_SVE_ZREG_SIZE (vq
));
249 /* Check in the reg_buf if any of the Z registers are set after the
250 first 128 bits, or if any of the other SVE registers are set. */
252 for (int i
= 0; i
< AARCH64_SVE_Z_REGS_NUM
; i
++)
254 has_sve_state
|= reg_buf
->raw_compare (AARCH64_SVE_Z0_REGNUM
+ i
,
255 zero_reg
, sizeof (__int128_t
));
261 for (int i
= 0; i
< AARCH64_SVE_P_REGS_NUM
; i
++)
263 has_sve_state
|= reg_buf
->raw_compare (AARCH64_SVE_P0_REGNUM
+ i
,
270 has_sve_state
|= reg_buf
->raw_compare (AARCH64_SVE_FFR_REGNUM
,
273 /* If no SVE state exists, then use the existing fpsimd structure to
274 write out state and return. */
277 /* The collects of the Z registers will overflow the size of a vreg.
278 There is enough space in the structure to allow for this, but we
279 cannot overflow into the next register as we might not be
280 collecting every register. */
282 for (int i
= 0; i
< AARCH64_SVE_Z_REGS_NUM
; i
++)
285 == reg_buf
->get_register_status (AARCH64_SVE_Z0_REGNUM
+ i
))
287 reg_buf
->raw_collect (AARCH64_SVE_Z0_REGNUM
+ i
, zero_reg
);
288 memcpy (&fpsimd
->vregs
[i
], zero_reg
, sizeof (__int128_t
));
292 if (REG_VALID
== reg_buf
->get_register_status (AARCH64_FPSR_REGNUM
))
293 reg_buf
->raw_collect (AARCH64_FPSR_REGNUM
, &fpsimd
->fpsr
);
294 if (REG_VALID
== reg_buf
->get_register_status (AARCH64_FPCR_REGNUM
))
295 reg_buf
->raw_collect (AARCH64_FPCR_REGNUM
, &fpsimd
->fpcr
);
300 /* Otherwise, reformat the fpsimd structure into a full SVE set, by
301 expanding the V registers (working backwards so we don't splat
302 registers before they are copied) and using null for everything else.
303 Note that enough space for a full SVE dump was originally allocated
306 header
->flags
|= SVE_PT_REGS_SVE
;
307 header
->size
= SVE_PT_SIZE (vq
, SVE_PT_REGS_SVE
);
309 memcpy (base
+ SVE_PT_SVE_FPSR_OFFSET (vq
), &fpsimd
->fpsr
,
311 memcpy (base
+ SVE_PT_SVE_FPCR_OFFSET (vq
), &fpsimd
->fpcr
,
314 for (int i
= AARCH64_SVE_Z_REGS_NUM
; i
>= 0 ; i
--)
316 memcpy (base
+ SVE_PT_SVE_ZREG_OFFSET (vq
, i
), &fpsimd
->vregs
[i
],
317 sizeof (__int128_t
));
321 /* Replace the kernel values with those from reg_buf. */
323 for (int i
= 0; i
< AARCH64_SVE_Z_REGS_NUM
; i
++)
324 if (REG_VALID
== reg_buf
->get_register_status (AARCH64_SVE_Z0_REGNUM
+ i
))
325 reg_buf
->raw_collect (AARCH64_SVE_Z0_REGNUM
+ i
,
326 base
+ SVE_PT_SVE_ZREG_OFFSET (vq
, i
));
328 for (int i
= 0; i
< AARCH64_SVE_P_REGS_NUM
; i
++)
329 if (REG_VALID
== reg_buf
->get_register_status (AARCH64_SVE_P0_REGNUM
+ i
))
330 reg_buf
->raw_collect (AARCH64_SVE_P0_REGNUM
+ i
,
331 base
+ SVE_PT_SVE_PREG_OFFSET (vq
, i
));
333 if (REG_VALID
== reg_buf
->get_register_status (AARCH64_SVE_FFR_REGNUM
))
334 reg_buf
->raw_collect (AARCH64_SVE_FFR_REGNUM
,
335 base
+ SVE_PT_SVE_FFR_OFFSET (vq
));
336 if (REG_VALID
== reg_buf
->get_register_status (AARCH64_FPSR_REGNUM
))
337 reg_buf
->raw_collect (AARCH64_FPSR_REGNUM
,
338 base
+ SVE_PT_SVE_FPSR_OFFSET (vq
));
339 if (REG_VALID
== reg_buf
->get_register_status (AARCH64_FPCR_REGNUM
))
340 reg_buf
->raw_collect (AARCH64_FPCR_REGNUM
,
341 base
+ SVE_PT_SVE_FPCR_OFFSET (vq
));