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