xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/nat/aarch64-sve-linux-ptrace.c (revision 4ac76180e904e771b9d522c7e57296d371f06499)
1 /* Common target dependent for AArch64 systems.
2 
3    Copyright (C) 2018-2020 Free Software Foundation, Inc.
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>
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"
29 
30 /* See nat/aarch64-sve-linux-ptrace.h.  */
31 
32 uint64_t
33 aarch64_sve_get_vq (int tid)
34 {
35   struct iovec iovec;
36   struct user_sve_header header;
37 
38   iovec.iov_len = sizeof (header);
39   iovec.iov_base = &header;
40 
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.  */
44 
45   if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_SVE, &iovec) < 0)
46     {
47       /* SVE is not supported.  */
48       return 0;
49     }
50 
51   uint64_t vq = sve_vq_from_vl (header.vl);
52 
53   if (!sve_vl_valid (header.vl))
54     {
55       warning (_("Invalid SVE state from kernel; SVE disabled."));
56       return 0;
57     }
58 
59   return vq;
60 }
61 
62 /* See nat/aarch64-sve-linux-ptrace.h.  */
63 
64 bool
65 aarch64_sve_set_vq (int tid, uint64_t vq)
66 {
67   struct iovec iovec;
68   struct user_sve_header header;
69 
70   iovec.iov_len = sizeof (header);
71   iovec.iov_base = &header;
72 
73   if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_SVE, &iovec) < 0)
74     {
75       /* SVE is not supported.  */
76       return false;
77     }
78 
79   header.vl = sve_vl_from_vq (vq);
80 
81   if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_SVE, &iovec) < 0)
82     {
83       /* Vector length change failed.  */
84       return false;
85     }
86 
87   return true;
88 }
89 
90 /* See nat/aarch64-sve-linux-ptrace.h.  */
91 
92 bool
93 aarch64_sve_set_vq (int tid, struct reg_buffer_common *reg_buf)
94 {
95   uint64_t reg_vg = 0;
96 
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
100      registers.  */
101   if (reg_buf->get_register_status (AARCH64_SVE_VG_REGNUM) != REG_VALID)
102   {
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);
106 
107     /* If something went wrong, just bail out.  */
108     if (vq == 0)
109       return false;
110 
111     reg_vg = sve_vg_from_vq (vq);
112   }
113   else
114     reg_buf->raw_collect (AARCH64_SVE_VG_REGNUM, &reg_vg);
115 
116   return aarch64_sve_set_vq (tid, sve_vq_from_vg (reg_vg));
117 }
118 
119 /* See nat/aarch64-sve-linux-ptrace.h.  */
120 
121 std::unique_ptr<gdb_byte[]>
122 aarch64_sve_get_sveregs (int tid)
123 {
124   struct iovec iovec;
125   uint64_t vq = aarch64_sve_get_vq (tid);
126 
127   if (vq == 0)
128     perror_with_name (_("Unable to fetch SVE register header"));
129 
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.  */
134 
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 ();
138 
139   if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_SVE, &iovec) < 0)
140     perror_with_name (_("Unable to fetch SVE registers"));
141 
142   return buf;
143 }
144 
145 /* See nat/aarch64-sve-linux-ptrace.h.  */
146 
147 void
148 aarch64_sve_regs_copy_to_reg_buf (struct reg_buffer_common *reg_buf,
149 				  const void *buf)
150 {
151   char *base = (char *) buf;
152   struct user_sve_header *header = (struct user_sve_header *) buf;
153 
154   uint64_t vq = sve_vq_from_vl (header->vl);
155   uint64_t vg = sve_vg_from_vl (header->vl);
156 
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."));
161 
162   /* Update VG.  Note, the registers in the regcache will already be of the
163      correct length.  */
164   reg_buf->raw_supply (AARCH64_SVE_VG_REGNUM, &vg);
165 
166   if (HAS_SVE_STATE (*header))
167     {
168       /* The register dump contains a set of SVE registers.  */
169 
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));
173 
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));
177 
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));
184     }
185   else
186     {
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.  */
190 
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);
194 
195       /* Copy across the V registers from fpsimd structure to the Z registers,
196 	 ensuring the non overlapping state is set to null.  */
197 
198       memset (zero_reg, 0, SVE_PT_SVE_ZREG_SIZE (vq));
199 
200       for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++)
201 	{
202 	  memcpy (zero_reg, &fpsimd->vregs[i], sizeof (__int128_t));
203 	  reg_buf->raw_supply (AARCH64_SVE_Z0_REGNUM + i, zero_reg);
204 	}
205 
206       reg_buf->raw_supply (AARCH64_FPSR_REGNUM, &fpsimd->fpsr);
207       reg_buf->raw_supply (AARCH64_FPCR_REGNUM, &fpsimd->fpcr);
208 
209       /* Clear the SVE only registers.  */
210 
211       for (int i = 0; i < AARCH64_SVE_P_REGS_NUM; i++)
212 	reg_buf->raw_supply (AARCH64_SVE_P0_REGNUM + i, zero_reg);
213 
214       reg_buf->raw_supply (AARCH64_SVE_FFR_REGNUM, zero_reg);
215     }
216 }
217 
218 /* See nat/aarch64-sve-linux-ptrace.h.  */
219 
220 void
221 aarch64_sve_regs_copy_from_reg_buf (const struct reg_buffer_common *reg_buf,
222 				    void *buf)
223 {
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);
227 
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."));
232 
233   if (!HAS_SVE_STATE (*header))
234     {
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.  */
241 
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);
246 
247       memset (zero_reg, 0, SVE_PT_SVE_ZREG_SIZE (vq));
248 
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.  */
251 
252       for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++)
253 	{
254 	  has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_Z0_REGNUM + i,
255 						 zero_reg, sizeof (__int128_t));
256 	  if (has_sve_state)
257 	    break;
258 	}
259 
260       if (!has_sve_state)
261 	for (int i = 0; i < AARCH64_SVE_P_REGS_NUM; i++)
262 	  {
263 	    has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_P0_REGNUM + i,
264 						   zero_reg, 0);
265 	    if (has_sve_state)
266 	      break;
267 	  }
268 
269       if (!has_sve_state)
270 	  has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_FFR_REGNUM,
271 						 zero_reg, 0);
272 
273       /* If no SVE state exists, then use the existing fpsimd structure to
274 	 write out state and return.  */
275       if (!has_sve_state)
276 	{
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.  */
281 
282 	  for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++)
283 	    {
284 	      if (REG_VALID
285 		  == reg_buf->get_register_status (AARCH64_SVE_Z0_REGNUM + i))
286 		{
287 		  reg_buf->raw_collect (AARCH64_SVE_Z0_REGNUM + i, zero_reg);
288 		  memcpy (&fpsimd->vregs[i], zero_reg, sizeof (__int128_t));
289 		}
290 	    }
291 
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);
296 
297 	  return;
298 	}
299 
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
304 	 for base.  */
305 
306       header->flags |= SVE_PT_REGS_SVE;
307       header->size = SVE_PT_SIZE (vq, SVE_PT_REGS_SVE);
308 
309       memcpy (base + SVE_PT_SVE_FPSR_OFFSET (vq), &fpsimd->fpsr,
310 	      sizeof (uint32_t));
311       memcpy (base + SVE_PT_SVE_FPCR_OFFSET (vq), &fpsimd->fpcr,
312 	      sizeof (uint32_t));
313 
314       for (int i = AARCH64_SVE_Z_REGS_NUM; i >= 0 ; i--)
315 	{
316 	  memcpy (base + SVE_PT_SVE_ZREG_OFFSET (vq, i), &fpsimd->vregs[i],
317 		  sizeof (__int128_t));
318 	}
319     }
320 
321   /* Replace the kernel values with those from reg_buf.  */
322 
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));
327 
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));
332 
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));
342 
343 }
344