1e8d8bef9SDimitry Andric //===-- LinuxPTraceDefines_arm64sve.h ------------------------- -*- C++ -*-===//
2e8d8bef9SDimitry Andric //
3e8d8bef9SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e8d8bef9SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e8d8bef9SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e8d8bef9SDimitry Andric //
7e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===//
8e8d8bef9SDimitry Andric
9e8d8bef9SDimitry Andric #ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LINUXPTRACEDEFINES_ARM64SVE_H
10e8d8bef9SDimitry Andric #define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LINUXPTRACEDEFINES_ARM64SVE_H
11e8d8bef9SDimitry Andric
12fe6060f1SDimitry Andric #include <cstdint>
13e8d8bef9SDimitry Andric
14e8d8bef9SDimitry Andric namespace lldb_private {
15e8d8bef9SDimitry Andric namespace sve {
16e8d8bef9SDimitry Andric
17e8d8bef9SDimitry Andric /*
18e8d8bef9SDimitry Andric * The SVE architecture leaves space for future expansion of the
19e8d8bef9SDimitry Andric * vector length beyond its initial architectural limit of 2048 bits
20e8d8bef9SDimitry Andric * (16 quadwords).
21e8d8bef9SDimitry Andric *
22e8d8bef9SDimitry Andric * See <Linux kernel source tree>/Documentation/arm64/sve.rst for a description
23e8d8bef9SDimitry Andric * of the vl/vq terminology.
24e8d8bef9SDimitry Andric */
25e8d8bef9SDimitry Andric
26e8d8bef9SDimitry Andric const uint16_t vq_bytes = 16; /* number of bytes per quadword */
27e8d8bef9SDimitry Andric
28e8d8bef9SDimitry Andric const uint16_t vq_min = 1;
29e8d8bef9SDimitry Andric const uint16_t vq_max = 512;
30e8d8bef9SDimitry Andric
31e8d8bef9SDimitry Andric const uint16_t vl_min = vq_min * vq_bytes;
32e8d8bef9SDimitry Andric const uint16_t vl_max = vq_max * vq_bytes;
33e8d8bef9SDimitry Andric
34e8d8bef9SDimitry Andric const uint16_t num_of_zregs = 32;
35e8d8bef9SDimitry Andric const uint16_t num_of_pregs = 16;
36e8d8bef9SDimitry Andric
vl_valid(uint16_t vl)37e8d8bef9SDimitry Andric inline uint16_t vl_valid(uint16_t vl) {
38e8d8bef9SDimitry Andric return (vl % vq_bytes == 0 && vl >= vl_min && vl <= vl_max);
39e8d8bef9SDimitry Andric }
40e8d8bef9SDimitry Andric
vq_from_vl(uint16_t vl)41e8d8bef9SDimitry Andric inline uint16_t vq_from_vl(uint16_t vl) { return vl / vq_bytes; }
vl_from_vq(uint16_t vq)42e8d8bef9SDimitry Andric inline uint16_t vl_from_vq(uint16_t vq) { return vq * vq_bytes; }
43e8d8bef9SDimitry Andric
44e8d8bef9SDimitry Andric /* A new signal frame record sve_context encodes the SVE Registers on signal
45e8d8bef9SDimitry Andric * delivery. sve_context struct definition may be included in asm/sigcontext.h.
46e8d8bef9SDimitry Andric * We define sve_context_size which will be used by LLDB sve helper functions.
47e8d8bef9SDimitry Andric * More information on sve_context can be found in Linux kernel source tree at
48e8d8bef9SDimitry Andric * Documentation/arm64/sve.rst.
49e8d8bef9SDimitry Andric */
50e8d8bef9SDimitry Andric
51e8d8bef9SDimitry Andric const uint16_t sve_context_size = 16;
52e8d8bef9SDimitry Andric
53e8d8bef9SDimitry Andric /*
54e8d8bef9SDimitry Andric * If the SVE registers are currently live for the thread at signal delivery,
55e8d8bef9SDimitry Andric * sve_context.head.size >=
56e8d8bef9SDimitry Andric * SigContextSize(vq_from_vl(sve_context.vl))
57e8d8bef9SDimitry Andric * and the register data may be accessed using the Sig*() functions.
58e8d8bef9SDimitry Andric *
59e8d8bef9SDimitry Andric * If sve_context.head.size <
60e8d8bef9SDimitry Andric * SigContextSize(vq_from_vl(sve_context.vl)),
61e8d8bef9SDimitry Andric * the SVE registers were not live for the thread and no register data
62e8d8bef9SDimitry Andric * is included: in this case, the Sig*() functions should not be
63e8d8bef9SDimitry Andric * used except for this check.
64e8d8bef9SDimitry Andric *
65e8d8bef9SDimitry Andric * The same convention applies when returning from a signal: a caller
66e8d8bef9SDimitry Andric * will need to remove or resize the sve_context block if it wants to
67e8d8bef9SDimitry Andric * make the SVE registers live when they were previously non-live or
68fe6060f1SDimitry Andric * vice-versa. This may require the caller to allocate fresh
69e8d8bef9SDimitry Andric * memory and/or move other context blocks in the signal frame.
70e8d8bef9SDimitry Andric *
71e8d8bef9SDimitry Andric * Changing the vector length during signal return is not permitted:
72e8d8bef9SDimitry Andric * sve_context.vl must equal the thread's current vector length when
73e8d8bef9SDimitry Andric * doing a sigreturn.
74e8d8bef9SDimitry Andric *
75e8d8bef9SDimitry Andric *
76e8d8bef9SDimitry Andric * Note: for all these functions, the "vq" argument denotes the SVE
77e8d8bef9SDimitry Andric * vector length in quadwords (i.e., units of 128 bits).
78e8d8bef9SDimitry Andric *
79e8d8bef9SDimitry Andric * The correct way to obtain vq is to use vq_from_vl(vl). The
80e8d8bef9SDimitry Andric * result is valid if and only if vl_valid(vl) is true. This is
81e8d8bef9SDimitry Andric * guaranteed for a struct sve_context written by the kernel.
82e8d8bef9SDimitry Andric *
83e8d8bef9SDimitry Andric *
84e8d8bef9SDimitry Andric * Additional functions describe the contents and layout of the payload.
85e8d8bef9SDimitry Andric * For each, Sig*Offset(args) is the start offset relative to
86e8d8bef9SDimitry Andric * the start of struct sve_context, and Sig*Size(args) is the
87e8d8bef9SDimitry Andric * size in bytes:
88e8d8bef9SDimitry Andric *
89e8d8bef9SDimitry Andric * x type description
90e8d8bef9SDimitry Andric * - ---- -----------
91e8d8bef9SDimitry Andric * REGS the entire SVE context
92e8d8bef9SDimitry Andric *
93e8d8bef9SDimitry Andric * ZREGS __uint128_t[num_of_zregs][vq] all Z-registers
94e8d8bef9SDimitry Andric * ZREG __uint128_t[vq] individual Z-register Zn
95e8d8bef9SDimitry Andric *
96e8d8bef9SDimitry Andric * PREGS uint16_t[num_of_pregs][vq] all P-registers
97e8d8bef9SDimitry Andric * PREG uint16_t[vq] individual P-register Pn
98e8d8bef9SDimitry Andric *
99e8d8bef9SDimitry Andric * FFR uint16_t[vq] first-fault status register
100e8d8bef9SDimitry Andric *
101e8d8bef9SDimitry Andric * Additional data might be appended in the future.
102e8d8bef9SDimitry Andric */
103e8d8bef9SDimitry Andric
SigZRegSize(uint16_t vq)104e8d8bef9SDimitry Andric inline uint16_t SigZRegSize(uint16_t vq) { return vq * vq_bytes; }
SigPRegSize(uint16_t vq)105e8d8bef9SDimitry Andric inline uint16_t SigPRegSize(uint16_t vq) { return vq * vq_bytes / 8; }
SigFFRSize(uint16_t vq)106e8d8bef9SDimitry Andric inline uint16_t SigFFRSize(uint16_t vq) { return SigPRegSize(vq); }
107e8d8bef9SDimitry Andric
SigRegsOffset()108e8d8bef9SDimitry Andric inline uint32_t SigRegsOffset() {
109e8d8bef9SDimitry Andric return (sve_context_size + vq_bytes - 1) / vq_bytes * vq_bytes;
110e8d8bef9SDimitry Andric }
111e8d8bef9SDimitry Andric
SigZRegsOffset()112e8d8bef9SDimitry Andric inline uint32_t SigZRegsOffset() { return SigRegsOffset(); }
113e8d8bef9SDimitry Andric
SigZRegOffset(uint16_t vq,uint16_t n)114e8d8bef9SDimitry Andric inline uint32_t SigZRegOffset(uint16_t vq, uint16_t n) {
115e8d8bef9SDimitry Andric return SigRegsOffset() + SigZRegSize(vq) * n;
116e8d8bef9SDimitry Andric }
117e8d8bef9SDimitry Andric
SigZRegsSize(uint16_t vq)118e8d8bef9SDimitry Andric inline uint32_t SigZRegsSize(uint16_t vq) {
119e8d8bef9SDimitry Andric return SigZRegOffset(vq, num_of_zregs) - SigRegsOffset();
120e8d8bef9SDimitry Andric }
121e8d8bef9SDimitry Andric
SigPRegsOffset(uint16_t vq)122e8d8bef9SDimitry Andric inline uint32_t SigPRegsOffset(uint16_t vq) {
123e8d8bef9SDimitry Andric return SigRegsOffset() + SigZRegsSize(vq);
124e8d8bef9SDimitry Andric }
125e8d8bef9SDimitry Andric
SigPRegOffset(uint16_t vq,uint16_t n)126e8d8bef9SDimitry Andric inline uint32_t SigPRegOffset(uint16_t vq, uint16_t n) {
127e8d8bef9SDimitry Andric return SigPRegsOffset(vq) + SigPRegSize(vq) * n;
128e8d8bef9SDimitry Andric }
129e8d8bef9SDimitry Andric
SigpRegsSize(uint16_t vq)130e8d8bef9SDimitry Andric inline uint32_t SigpRegsSize(uint16_t vq) {
131e8d8bef9SDimitry Andric return SigPRegOffset(vq, num_of_pregs) - SigPRegsOffset(vq);
132e8d8bef9SDimitry Andric }
133e8d8bef9SDimitry Andric
SigFFROffset(uint16_t vq)134e8d8bef9SDimitry Andric inline uint32_t SigFFROffset(uint16_t vq) {
135e8d8bef9SDimitry Andric return SigPRegsOffset(vq) + SigpRegsSize(vq);
136e8d8bef9SDimitry Andric }
137e8d8bef9SDimitry Andric
SigRegsSize(uint16_t vq)138e8d8bef9SDimitry Andric inline uint32_t SigRegsSize(uint16_t vq) {
139e8d8bef9SDimitry Andric return SigFFROffset(vq) + SigFFRSize(vq) - SigRegsOffset();
140e8d8bef9SDimitry Andric }
141e8d8bef9SDimitry Andric
SVESigContextSize(uint16_t vq)142e8d8bef9SDimitry Andric inline uint32_t SVESigContextSize(uint16_t vq) {
143e8d8bef9SDimitry Andric return SigRegsOffset() + SigRegsSize(vq);
144e8d8bef9SDimitry Andric }
145e8d8bef9SDimitry Andric
146e8d8bef9SDimitry Andric struct user_sve_header {
147e8d8bef9SDimitry Andric uint32_t size; /* total meaningful regset content in bytes */
148e8d8bef9SDimitry Andric uint32_t max_size; /* maxmium possible size for this thread */
149e8d8bef9SDimitry Andric uint16_t vl; /* current vector length */
150e8d8bef9SDimitry Andric uint16_t max_vl; /* maximum possible vector length */
151e8d8bef9SDimitry Andric uint16_t flags;
152e8d8bef9SDimitry Andric uint16_t reserved;
153e8d8bef9SDimitry Andric };
154e8d8bef9SDimitry Andric
155*5f757f3fSDimitry Andric using user_za_header = user_sve_header;
156*5f757f3fSDimitry Andric
157e8d8bef9SDimitry Andric /* Definitions for user_sve_header.flags: */
158e8d8bef9SDimitry Andric const uint16_t ptrace_regs_mask = 1 << 0;
159e8d8bef9SDimitry Andric const uint16_t ptrace_regs_fpsimd = 0;
160e8d8bef9SDimitry Andric const uint16_t ptrace_regs_sve = ptrace_regs_mask;
161e8d8bef9SDimitry Andric
162e8d8bef9SDimitry Andric /*
163e8d8bef9SDimitry Andric * The remainder of the SVE state follows struct user_sve_header. The
164e8d8bef9SDimitry Andric * total size of the SVE state (including header) depends on the
165e8d8bef9SDimitry Andric * metadata in the header: PTraceSize(vq, flags) gives the total size
166e8d8bef9SDimitry Andric * of the state in bytes, including the header.
167e8d8bef9SDimitry Andric *
168e8d8bef9SDimitry Andric * Refer to <asm/sigcontext.h> for details of how to pass the correct
169e8d8bef9SDimitry Andric * "vq" argument to these macros.
170e8d8bef9SDimitry Andric */
171e8d8bef9SDimitry Andric
172e8d8bef9SDimitry Andric /* Offset from the start of struct user_sve_header to the register data */
PTraceRegsOffset()173e8d8bef9SDimitry Andric inline uint16_t PTraceRegsOffset() {
174e8d8bef9SDimitry Andric return (sizeof(struct user_sve_header) + vq_bytes - 1) / vq_bytes * vq_bytes;
175e8d8bef9SDimitry Andric }
176e8d8bef9SDimitry Andric
177e8d8bef9SDimitry Andric /*
178e8d8bef9SDimitry Andric * The register data content and layout depends on the value of the
179e8d8bef9SDimitry Andric * flags field.
180e8d8bef9SDimitry Andric */
181e8d8bef9SDimitry Andric
182e8d8bef9SDimitry Andric /*
183e8d8bef9SDimitry Andric * (flags & ptrace_regs_mask) == ptrace_regs_fpsimd case:
184e8d8bef9SDimitry Andric *
185e8d8bef9SDimitry Andric * The payload starts at offset PTraceFPSIMDOffset, and is of type
186e8d8bef9SDimitry Andric * struct user_fpsimd_state. Additional data might be appended in the
187e8d8bef9SDimitry Andric * future: use PTraceFPSIMDSize(vq, flags) to compute the total size.
188e8d8bef9SDimitry Andric * PTraceFPSIMDSize(vq, flags) will never be less than
189e8d8bef9SDimitry Andric * sizeof(struct user_fpsimd_state).
190e8d8bef9SDimitry Andric */
191e8d8bef9SDimitry Andric
192e8d8bef9SDimitry Andric const uint32_t ptrace_fpsimd_offset = PTraceRegsOffset();
193e8d8bef9SDimitry Andric
194e8d8bef9SDimitry Andric /* Return size of struct user_fpsimd_state from asm/ptrace.h */
PTraceFPSIMDSize(uint16_t vq,uint16_t flags)195e8d8bef9SDimitry Andric inline uint32_t PTraceFPSIMDSize(uint16_t vq, uint16_t flags) { return 528; }
196e8d8bef9SDimitry Andric
197e8d8bef9SDimitry Andric /*
198e8d8bef9SDimitry Andric * (flags & ptrace_regs_mask) == ptrace_regs_sve case:
199e8d8bef9SDimitry Andric *
200e8d8bef9SDimitry Andric * The payload starts at offset PTraceSVEOffset, and is of size
201e8d8bef9SDimitry Andric * PTraceSVESize(vq, flags).
202e8d8bef9SDimitry Andric *
203e8d8bef9SDimitry Andric * Additional functions describe the contents and layout of the payload.
204e8d8bef9SDimitry Andric * For each, PTrace*X*Offset(args) is the start offset relative to
205e8d8bef9SDimitry Andric * the start of struct user_sve_header, and PTrace*X*Size(args) is
206e8d8bef9SDimitry Andric * the size in bytes:
207e8d8bef9SDimitry Andric *
208e8d8bef9SDimitry Andric * x type description
209e8d8bef9SDimitry Andric * - ---- -----------
210e8d8bef9SDimitry Andric * ZREGS \
211e8d8bef9SDimitry Andric * ZREG |
212e8d8bef9SDimitry Andric * PREGS | refer to <asm/sigcontext.h>
213e8d8bef9SDimitry Andric * PREG |
214e8d8bef9SDimitry Andric * FFR /
215e8d8bef9SDimitry Andric *
216e8d8bef9SDimitry Andric * FPSR uint32_t FPSR
217e8d8bef9SDimitry Andric * FPCR uint32_t FPCR
218e8d8bef9SDimitry Andric *
219e8d8bef9SDimitry Andric * Additional data might be appended in the future.
220e8d8bef9SDimitry Andric */
221e8d8bef9SDimitry Andric
PTraceZRegSize(uint16_t vq)222e8d8bef9SDimitry Andric inline uint32_t PTraceZRegSize(uint16_t vq) { return SigZRegSize(vq); }
223e8d8bef9SDimitry Andric
PTracePRegSize(uint16_t vq)224e8d8bef9SDimitry Andric inline uint32_t PTracePRegSize(uint16_t vq) { return SigPRegSize(vq); }
225e8d8bef9SDimitry Andric
PTraceFFRSize(uint16_t vq)226e8d8bef9SDimitry Andric inline uint32_t PTraceFFRSize(uint16_t vq) { return SigFFRSize(vq); }
227e8d8bef9SDimitry Andric
228e8d8bef9SDimitry Andric const uint32_t fpsr_size = sizeof(uint32_t);
229e8d8bef9SDimitry Andric const uint32_t fpcr_size = sizeof(uint32_t);
230e8d8bef9SDimitry Andric
SigToPTrace(uint32_t offset)231e8d8bef9SDimitry Andric inline uint32_t SigToPTrace(uint32_t offset) {
232e8d8bef9SDimitry Andric return offset - SigRegsOffset() + PTraceRegsOffset();
233e8d8bef9SDimitry Andric }
234e8d8bef9SDimitry Andric
235e8d8bef9SDimitry Andric const uint32_t ptrace_sve_offset = PTraceRegsOffset();
236e8d8bef9SDimitry Andric
PTraceZRegsOffset(uint16_t vq)237e8d8bef9SDimitry Andric inline uint32_t PTraceZRegsOffset(uint16_t vq) {
238e8d8bef9SDimitry Andric return SigToPTrace(SigZRegsOffset());
239e8d8bef9SDimitry Andric }
240e8d8bef9SDimitry Andric
PTraceZRegOffset(uint16_t vq,uint16_t n)241e8d8bef9SDimitry Andric inline uint32_t PTraceZRegOffset(uint16_t vq, uint16_t n) {
242e8d8bef9SDimitry Andric return SigToPTrace(SigZRegOffset(vq, n));
243e8d8bef9SDimitry Andric }
244e8d8bef9SDimitry Andric
PTraceZRegsSize(uint16_t vq)245e8d8bef9SDimitry Andric inline uint32_t PTraceZRegsSize(uint16_t vq) {
246e8d8bef9SDimitry Andric return PTraceZRegOffset(vq, num_of_zregs) - SigToPTrace(SigRegsOffset());
247e8d8bef9SDimitry Andric }
248e8d8bef9SDimitry Andric
PTracePRegsOffset(uint16_t vq)249e8d8bef9SDimitry Andric inline uint32_t PTracePRegsOffset(uint16_t vq) {
250e8d8bef9SDimitry Andric return SigToPTrace(SigPRegsOffset(vq));
251e8d8bef9SDimitry Andric }
252e8d8bef9SDimitry Andric
PTracePRegOffset(uint16_t vq,uint16_t n)253e8d8bef9SDimitry Andric inline uint32_t PTracePRegOffset(uint16_t vq, uint16_t n) {
254e8d8bef9SDimitry Andric return SigToPTrace(SigPRegOffset(vq, n));
255e8d8bef9SDimitry Andric }
256e8d8bef9SDimitry Andric
PTracePRegsSize(uint16_t vq)257e8d8bef9SDimitry Andric inline uint32_t PTracePRegsSize(uint16_t vq) {
258e8d8bef9SDimitry Andric return PTracePRegOffset(vq, num_of_pregs) - PTracePRegsOffset(vq);
259e8d8bef9SDimitry Andric }
260e8d8bef9SDimitry Andric
PTraceFFROffset(uint16_t vq)261e8d8bef9SDimitry Andric inline uint32_t PTraceFFROffset(uint16_t vq) {
262e8d8bef9SDimitry Andric return SigToPTrace(SigFFROffset(vq));
263e8d8bef9SDimitry Andric }
264e8d8bef9SDimitry Andric
PTraceFPSROffset(uint16_t vq)265e8d8bef9SDimitry Andric inline uint32_t PTraceFPSROffset(uint16_t vq) {
266e8d8bef9SDimitry Andric return (PTraceFFROffset(vq) + PTraceFFRSize(vq) + (vq_bytes - 1)) / vq_bytes *
267e8d8bef9SDimitry Andric vq_bytes;
268e8d8bef9SDimitry Andric }
269e8d8bef9SDimitry Andric
PTraceFPCROffset(uint16_t vq)270e8d8bef9SDimitry Andric inline uint32_t PTraceFPCROffset(uint16_t vq) {
271e8d8bef9SDimitry Andric return PTraceFPSROffset(vq) + fpsr_size;
272e8d8bef9SDimitry Andric }
273e8d8bef9SDimitry Andric
274e8d8bef9SDimitry Andric /*
275e8d8bef9SDimitry Andric * Any future extension appended after FPCR must be aligned to the next
276e8d8bef9SDimitry Andric * 128-bit boundary.
277e8d8bef9SDimitry Andric */
278e8d8bef9SDimitry Andric
PTraceSVESize(uint16_t vq,uint16_t flags)279e8d8bef9SDimitry Andric inline uint32_t PTraceSVESize(uint16_t vq, uint16_t flags) {
280e8d8bef9SDimitry Andric return (PTraceFPCROffset(vq) + fpcr_size - ptrace_sve_offset + vq_bytes - 1) /
281e8d8bef9SDimitry Andric vq_bytes * vq_bytes;
282e8d8bef9SDimitry Andric }
283e8d8bef9SDimitry Andric
PTraceSize(uint16_t vq,uint16_t flags)284e8d8bef9SDimitry Andric inline uint32_t PTraceSize(uint16_t vq, uint16_t flags) {
285e8d8bef9SDimitry Andric return (flags & ptrace_regs_mask) == ptrace_regs_sve
286e8d8bef9SDimitry Andric ? ptrace_sve_offset + PTraceSVESize(vq, flags)
287e8d8bef9SDimitry Andric : ptrace_fpsimd_offset + PTraceFPSIMDSize(vq, flags);
288e8d8bef9SDimitry Andric }
289e8d8bef9SDimitry Andric
290e8d8bef9SDimitry Andric } // namespace SVE
291e8d8bef9SDimitry Andric } // namespace lldb_private
292e8d8bef9SDimitry Andric
293e8d8bef9SDimitry Andric #endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LINUXPTRACEDEFINES_ARM64SVE_H
294