1 /* Common target dependent for AArch64 systems.
3 Copyright (C) 2018-2019 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 "common/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 "common/common-regcache.h"
28 #include "common/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
)
95 if (reg_buf
->get_register_status (AARCH64_SVE_VG_REGNUM
) != REG_VALID
)
99 reg_buf
->raw_collect (AARCH64_SVE_VG_REGNUM
, ®_vg
);
101 return aarch64_sve_set_vq (tid
, sve_vq_from_vg (reg_vg
));
104 /* See nat/aarch64-sve-linux-ptrace.h. */
106 std::unique_ptr
<gdb_byte
[]>
107 aarch64_sve_get_sveregs (int tid
)
110 uint64_t vq
= aarch64_sve_get_vq (tid
);
113 perror_with_name (_("Unable to fetch SVE register header"));
115 /* A ptrace call with NT_ARM_SVE will return a header followed by either a
116 dump of all the SVE and FP registers, or an fpsimd structure (identical to
117 the one returned by NT_FPREGSET) if the kernel has not yet executed any
118 SVE code. Make sure we allocate enough space for a full SVE dump. */
120 iovec
.iov_len
= SVE_PT_SIZE (vq
, SVE_PT_REGS_SVE
);
121 std::unique_ptr
<gdb_byte
[]> buf (new gdb_byte
[iovec
.iov_len
]);
122 iovec
.iov_base
= buf
.get ();
124 if (ptrace (PTRACE_GETREGSET
, tid
, NT_ARM_SVE
, &iovec
) < 0)
125 perror_with_name (_("Unable to fetch SVE registers"));
130 /* See nat/aarch64-sve-linux-ptrace.h. */
133 aarch64_sve_regs_copy_to_reg_buf (struct reg_buffer_common
*reg_buf
,
136 char *base
= (char *) buf
;
137 struct user_sve_header
*header
= (struct user_sve_header
*) buf
;
139 uint64_t vq
= sve_vq_from_vl (header
->vl
);
140 uint64_t vg
= sve_vg_from_vl (header
->vl
);
142 /* Sanity check the data in the header. */
143 if (!sve_vl_valid (header
->vl
)
144 || SVE_PT_SIZE (vq
, header
->flags
) != header
->size
)
145 error (_("Invalid SVE header from kernel."));
147 /* Update VG. Note, the registers in the regcache will already be of the
149 reg_buf
->raw_supply (AARCH64_SVE_VG_REGNUM
, &vg
);
151 if (HAS_SVE_STATE (*header
))
153 /* The register dump contains a set of SVE registers. */
155 for (int i
= 0; i
< AARCH64_SVE_Z_REGS_NUM
; i
++)
156 reg_buf
->raw_supply (AARCH64_SVE_Z0_REGNUM
+ i
,
157 base
+ SVE_PT_SVE_ZREG_OFFSET (vq
, i
));
159 for (int i
= 0; i
< AARCH64_SVE_P_REGS_NUM
; i
++)
160 reg_buf
->raw_supply (AARCH64_SVE_P0_REGNUM
+ i
,
161 base
+ SVE_PT_SVE_PREG_OFFSET (vq
, i
));
163 reg_buf
->raw_supply (AARCH64_SVE_FFR_REGNUM
,
164 base
+ SVE_PT_SVE_FFR_OFFSET (vq
));
165 reg_buf
->raw_supply (AARCH64_FPSR_REGNUM
,
166 base
+ SVE_PT_SVE_FPSR_OFFSET (vq
));
167 reg_buf
->raw_supply (AARCH64_FPCR_REGNUM
,
168 base
+ SVE_PT_SVE_FPCR_OFFSET (vq
));
172 /* There is no SVE state yet - the register dump contains a fpsimd
173 structure instead. These registers still exist in the hardware, but
174 the kernel has not yet initialised them, and so they will be null. */
176 char *zero_reg
= (char *) alloca (SVE_PT_SVE_ZREG_SIZE (vq
));
177 struct user_fpsimd_state
*fpsimd
178 = (struct user_fpsimd_state
*)(base
+ SVE_PT_FPSIMD_OFFSET
);
180 /* Copy across the V registers from fpsimd structure to the Z registers,
181 ensuring the non overlapping state is set to null. */
183 memset (zero_reg
, 0, SVE_PT_SVE_ZREG_SIZE (vq
));
185 for (int i
= 0; i
< AARCH64_SVE_Z_REGS_NUM
; i
++)
187 memcpy (zero_reg
, &fpsimd
->vregs
[i
], sizeof (__int128_t
));
188 reg_buf
->raw_supply (AARCH64_SVE_Z0_REGNUM
+ i
, zero_reg
);
191 reg_buf
->raw_supply (AARCH64_FPSR_REGNUM
, &fpsimd
->fpsr
);
192 reg_buf
->raw_supply (AARCH64_FPCR_REGNUM
, &fpsimd
->fpcr
);
194 /* Clear the SVE only registers. */
196 for (int i
= 0; i
< AARCH64_SVE_P_REGS_NUM
; i
++)
197 reg_buf
->raw_supply (AARCH64_SVE_P0_REGNUM
+ i
, zero_reg
);
199 reg_buf
->raw_supply (AARCH64_SVE_FFR_REGNUM
, zero_reg
);
203 /* See nat/aarch64-sve-linux-ptrace.h. */
206 aarch64_sve_regs_copy_from_reg_buf (const struct reg_buffer_common
*reg_buf
,
209 struct user_sve_header
*header
= (struct user_sve_header
*) buf
;
210 char *base
= (char *) buf
;
211 uint64_t vq
= sve_vq_from_vl (header
->vl
);
213 /* Sanity check the data in the header. */
214 if (!sve_vl_valid (header
->vl
)
215 || SVE_PT_SIZE (vq
, header
->flags
) != header
->size
)
216 error (_("Invalid SVE header from kernel."));
218 if (!HAS_SVE_STATE (*header
))
220 /* There is no SVE state yet - the register dump contains a fpsimd
221 structure instead. Where possible we want to write the reg_buf data
222 back to the kernel using the fpsimd structure. However, if we cannot
223 then we'll need to reformat the fpsimd into a full SVE structure,
224 resulting in the initialization of SVE state written back to the
225 kernel, which is why we try to avoid it. */
227 bool has_sve_state
= false;
228 char *zero_reg
= (char *) alloca (SVE_PT_SVE_ZREG_SIZE (vq
));
229 struct user_fpsimd_state
*fpsimd
230 = (struct user_fpsimd_state
*)(base
+ SVE_PT_FPSIMD_OFFSET
);
232 memset (zero_reg
, 0, SVE_PT_SVE_ZREG_SIZE (vq
));
234 /* Check in the reg_buf if any of the Z registers are set after the
235 first 128 bits, or if any of the other SVE registers are set. */
237 for (int i
= 0; i
< AARCH64_SVE_Z_REGS_NUM
; i
++)
239 has_sve_state
|= reg_buf
->raw_compare (AARCH64_SVE_Z0_REGNUM
+ i
,
240 zero_reg
, sizeof (__int128_t
));
246 for (int i
= 0; i
< AARCH64_SVE_P_REGS_NUM
; i
++)
248 has_sve_state
|= reg_buf
->raw_compare (AARCH64_SVE_P0_REGNUM
+ i
,
255 has_sve_state
|= reg_buf
->raw_compare (AARCH64_SVE_FFR_REGNUM
,
258 /* If no SVE state exists, then use the existing fpsimd structure to
259 write out state and return. */
262 /* The collects of the Z registers will overflow the size of a vreg.
263 There is enough space in the structure to allow for this, but we
264 cannot overflow into the next register as we might not be
265 collecting every register. */
267 for (int i
= 0; i
< AARCH64_SVE_Z_REGS_NUM
; i
++)
270 == reg_buf
->get_register_status (AARCH64_SVE_Z0_REGNUM
+ i
))
272 reg_buf
->raw_collect (AARCH64_SVE_Z0_REGNUM
+ i
, zero_reg
);
273 memcpy (&fpsimd
->vregs
[i
], zero_reg
, sizeof (__int128_t
));
277 if (REG_VALID
== reg_buf
->get_register_status (AARCH64_FPSR_REGNUM
))
278 reg_buf
->raw_collect (AARCH64_FPSR_REGNUM
, &fpsimd
->fpsr
);
279 if (REG_VALID
== reg_buf
->get_register_status (AARCH64_FPCR_REGNUM
))
280 reg_buf
->raw_collect (AARCH64_FPCR_REGNUM
, &fpsimd
->fpcr
);
285 /* Otherwise, reformat the fpsimd structure into a full SVE set, by
286 expanding the V registers (working backwards so we don't splat
287 registers before they are copied) and using null for everything else.
288 Note that enough space for a full SVE dump was originally allocated
291 header
->flags
|= SVE_PT_REGS_SVE
;
292 header
->size
= SVE_PT_SIZE (vq
, SVE_PT_REGS_SVE
);
294 memcpy (base
+ SVE_PT_SVE_FPSR_OFFSET (vq
), &fpsimd
->fpsr
,
296 memcpy (base
+ SVE_PT_SVE_FPCR_OFFSET (vq
), &fpsimd
->fpcr
,
299 for (int i
= AARCH64_SVE_Z_REGS_NUM
; i
>= 0 ; i
--)
301 memcpy (base
+ SVE_PT_SVE_ZREG_OFFSET (vq
, i
), &fpsimd
->vregs
[i
],
302 sizeof (__int128_t
));
306 /* Replace the kernel values with those from reg_buf. */
308 for (int i
= 0; i
< AARCH64_SVE_Z_REGS_NUM
; i
++)
309 if (REG_VALID
== reg_buf
->get_register_status (AARCH64_SVE_Z0_REGNUM
+ i
))
310 reg_buf
->raw_collect (AARCH64_SVE_Z0_REGNUM
+ i
,
311 base
+ SVE_PT_SVE_ZREG_OFFSET (vq
, i
));
313 for (int i
= 0; i
< AARCH64_SVE_P_REGS_NUM
; i
++)
314 if (REG_VALID
== reg_buf
->get_register_status (AARCH64_SVE_P0_REGNUM
+ i
))
315 reg_buf
->raw_collect (AARCH64_SVE_P0_REGNUM
+ i
,
316 base
+ SVE_PT_SVE_PREG_OFFSET (vq
, i
));
318 if (REG_VALID
== reg_buf
->get_register_status (AARCH64_SVE_FFR_REGNUM
))
319 reg_buf
->raw_collect (AARCH64_SVE_FFR_REGNUM
,
320 base
+ SVE_PT_SVE_FFR_OFFSET (vq
));
321 if (REG_VALID
== reg_buf
->get_register_status (AARCH64_FPSR_REGNUM
))
322 reg_buf
->raw_collect (AARCH64_FPSR_REGNUM
,
323 base
+ SVE_PT_SVE_FPSR_OFFSET (vq
));
324 if (REG_VALID
== reg_buf
->get_register_status (AARCH64_FPCR_REGNUM
))
325 reg_buf
->raw_collect (AARCH64_FPCR_REGNUM
,
326 base
+ SVE_PT_SVE_FPCR_OFFSET (vq
));