LLDB mainline
RegisterFlagsDetector_arm64.cpp
Go to the documentation of this file.
1//===-- RegisterFlagsDetector_arm64.cpp -----------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
11
12// This file is built on all systems because it is used by native processes and
13// core files, so we manually define the needed HWCAP values here.
14// These values are the same for Linux and FreeBSD.
15
16#define HWCAP_FPHP (1ULL << 9)
17#define HWCAP_ASIMDHP (1ULL << 10)
18#define HWCAP_DIT (1ULL << 24)
19#define HWCAP_SSBS (1ULL << 28)
20#define HWCAP_GCS (1ULL << 32)
21
22#define HWCAP2_BTI (1ULL << 17)
23#define HWCAP2_MTE (1ULL << 18)
24#define HWCAP2_AFP (1ULL << 20)
25#define HWCAP2_SME (1ULL << 23)
26#define HWCAP2_EBF16 (1ULL << 32)
27#define HWCAP2_FPMR (1ULL << 48)
28#define HWCAP2_POE (1ULL << 63)
29
30#define HWCAP3_MTE_STORE_ONLY (1ULL << 1)
31
32using namespace lldb_private;
33
35Arm64RegisterFlagsDetector::DetectPOREL0Fields(uint64_t hwcap, uint64_t hwcap2,
36 uint64_t hwcap3) {
37 (void)hwcap;
38 (void)hwcap3;
39
40 if (!(hwcap2 & HWCAP2_POE))
41 return {};
42
43 static const FieldEnum por_el0_perm_enum("por_el0_perm_enum",
44 {
45 {0b0000, "No Access"},
46 {0b0001, "Read"},
47 {0b0010, "Execute"},
48 {0b0011, "Read, Execute"},
49 {0b0100, "Write"},
50 {0b0101, "Write, Read"},
51 {0b0110, "Write, Execute"},
52 {0b0111, "Read, Write, Execute"},
53 });
54
55 return {
56 {"Perm15", 60, 63, &por_el0_perm_enum},
57 {"Perm14", 56, 59, &por_el0_perm_enum},
58 {"Perm13", 52, 55, &por_el0_perm_enum},
59 {"Perm12", 48, 51, &por_el0_perm_enum},
60 {"Perm11", 44, 47, &por_el0_perm_enum},
61 {"Perm10", 40, 43, &por_el0_perm_enum},
62 {"Perm9", 36, 39, &por_el0_perm_enum},
63 {"Perm8", 32, 35, &por_el0_perm_enum},
64 {"Perm7", 28, 31, &por_el0_perm_enum},
65 {"Perm6", 24, 27, &por_el0_perm_enum},
66 {"Perm5", 20, 23, &por_el0_perm_enum},
67 {"Perm4", 16, 19, &por_el0_perm_enum},
68 {"Perm3", 12, 15, &por_el0_perm_enum},
69 {"Perm2", 8, 11, &por_el0_perm_enum},
70 {"Perm1", 4, 7, &por_el0_perm_enum},
71 {"Perm0", 0, 3, &por_el0_perm_enum},
72 };
73}
74
76Arm64RegisterFlagsDetector::DetectFPMRFields(uint64_t hwcap, uint64_t hwcap2,
77 uint64_t hwcap3) {
78 (void)hwcap;
79 (void)hwcap3;
80
81 if (!(hwcap2 & HWCAP2_FPMR))
82 return {};
83
84 static const FieldEnum fp8_format_enum("fp8_format_enum", {
85 {0, "FP8_E5M2"},
86 {1, "FP8_E4M3"},
87 });
88 return {
89 {"LSCALE2", 32, 37},
90 {"NSCALE", 24, 31},
91 {"LSCALE", 16, 22},
92 {"OSC", 15},
93 {"OSM", 14},
94 {"F8D", 6, 8, &fp8_format_enum},
95 {"F8S2", 3, 5, &fp8_format_enum},
96 {"F8S1", 0, 2, &fp8_format_enum},
97 };
98}
99
102 uint64_t hwcap2,
103 uint64_t hwcap3) {
104 (void)hwcap2;
105 (void)hwcap3;
106
107 if (!(hwcap & HWCAP_GCS))
108 return {};
109
110 return {
111 {"PUSH", 2},
112 {"WRITE", 1},
113 {"ENABLE", 0},
114 };
115}
116
118Arm64RegisterFlagsDetector::DetectSVCRFields(uint64_t hwcap, uint64_t hwcap2,
119 uint64_t hwcap3) {
120 (void)hwcap;
121 (void)hwcap3;
122
123 if (!(hwcap2 & HWCAP2_SME))
124 return {};
125
126 // Represents the pseudo register that lldb-server builds, which itself
127 // matches the architectural register SCVR. The fields match SVCR in the Arm
128 // manual.
129 return {
130 {"ZA", 1},
131 {"SM", 0},
132 };
133}
134
137 uint64_t hwcap3) {
138 (void)hwcap;
139
140 if (!(hwcap2 & HWCAP2_MTE))
141 return {};
142
143 // Represents the contents of NT_ARM_TAGGED_ADDR_CTRL and the value passed
144 // to prctl(PR_TAGGED_ADDR_CTRL...). Fields are derived from the defines
145 // used to build the value.
146
147 std::vector<RegisterFlags::Field> fields;
148 fields.reserve(4);
149 if (hwcap3 & HWCAP3_MTE_STORE_ONLY)
150 fields.push_back({"STORE_ONLY", 19});
151
152 static const FieldEnum tcf_enum(
153 "tcf_enum",
154 {{0, "TCF_NONE"}, {1, "TCF_SYNC"}, {2, "TCF_ASYNC"}, {3, "TCF_ASYMM"}});
155
156 fields.insert(
157 std::end(fields),
158 {{"TAGS", 3, 18}, // 16 bit bitfield shifted up by PR_MTE_TAG_SHIFT.
159 {"TCF", 1, 2, &tcf_enum},
160 {"TAGGED_ADDR_ENABLE", 0}});
161
162 return fields;
163}
164
166Arm64RegisterFlagsDetector::DetectFPCRFields(uint64_t hwcap, uint64_t hwcap2,
167 uint64_t hwcap3) {
168 (void)hwcap3;
169
170 static const FieldEnum rmode_enum(
171 "rmode_enum", {{0, "RN"}, {1, "RP"}, {2, "RM"}, {3, "RZ"}});
172
173 std::vector<RegisterFlags::Field> fpcr_fields{
174 {"AHP", 26}, {"DN", 25}, {"FZ", 24}, {"RMode", 22, 23, &rmode_enum},
175 // Bits 21-20 are "Stride" which is unused in AArch64 state.
176 };
177
178 // FEAT_FP16 is indicated by the presence of FPHP (floating point half
179 // precision) and ASIMDHP (Advanced SIMD half precision) features.
180 if ((hwcap & HWCAP_FPHP) && (hwcap & HWCAP_ASIMDHP))
181 fpcr_fields.push_back({"FZ16", 19});
182
183 // Bits 18-16 are "Len" which is unused in AArch64 state.
184
185 fpcr_fields.push_back({"IDE", 15});
186
187 // Bit 14 is unused.
188 if (hwcap2 & HWCAP2_EBF16)
189 fpcr_fields.push_back({"EBF", 13});
190
191 fpcr_fields.push_back({"IXE", 12});
192 fpcr_fields.push_back({"UFE", 11});
193 fpcr_fields.push_back({"OFE", 10});
194 fpcr_fields.push_back({"DZE", 9});
195 fpcr_fields.push_back({"IOE", 8});
196 // Bits 7-3 reserved.
197
198 if (hwcap2 & HWCAP2_AFP) {
199 fpcr_fields.push_back({"NEP", 2});
200 fpcr_fields.push_back({"AH", 1});
201 fpcr_fields.push_back({"FIZ", 0});
202 }
203
204 return fpcr_fields;
205}
206
208Arm64RegisterFlagsDetector::DetectFPSRFields(uint64_t hwcap, uint64_t hwcap2,
209 uint64_t hwcap3) {
210 // fpsr's contents are constant.
211 (void)hwcap;
212 (void)hwcap2;
213 (void)hwcap3;
214
215 return {
216 // Bits 31-28 are N/Z/C/V, only used by AArch32.
217 {"QC", 27},
218 // Bits 26-8 reserved.
219 {"IDC", 7},
220 // Bits 6-5 reserved.
221 {"IXC", 4},
222 {"UFC", 3},
223 {"OFC", 2},
224 {"DZC", 1},
225 {"IOC", 0},
226 };
227}
228
230Arm64RegisterFlagsDetector::DetectCPSRFields(uint64_t hwcap, uint64_t hwcap2,
231 uint64_t hwcap3) {
232 (void)hwcap3;
233
234 // The fields here are a combination of the Arm manual's SPSR_EL1,
235 // plus a few changes where Linux has decided not to make use of them at all,
236 // or at least not from userspace.
237
238 // Status bits that are always present.
239 std::vector<RegisterFlags::Field> cpsr_fields{
240 {"N", 31}, {"Z", 30}, {"C", 29}, {"V", 28},
241 // Bits 27-26 reserved.
242 };
243
244 if (hwcap2 & HWCAP2_MTE)
245 cpsr_fields.push_back({"TCO", 25});
246 if (hwcap & HWCAP_DIT)
247 cpsr_fields.push_back({"DIT", 24});
248
249 // UAO and PAN are bits 23 and 22 and have no meaning for userspace so
250 // are treated as reserved by the kernels.
251
252 cpsr_fields.push_back({"SS", 21});
253 cpsr_fields.push_back({"IL", 20});
254 // Bits 19-14 reserved.
255
256 // Bit 13, ALLINT, requires FEAT_NMI that isn't relevant to userspace, and we
257 // can't detect either, don't show this field.
258 if (hwcap & HWCAP_SSBS)
259 cpsr_fields.push_back({"SSBS", 12});
260 if (hwcap2 & HWCAP2_BTI)
261 cpsr_fields.push_back({"BTYPE", 10, 11});
262
263 cpsr_fields.push_back({"D", 9});
264 cpsr_fields.push_back({"A", 8});
265 cpsr_fields.push_back({"I", 7});
266 cpsr_fields.push_back({"F", 6});
267 // Bit 5 reserved
268 // Called "M" in the ARMARM.
269 cpsr_fields.push_back({"nRW", 4});
270 // This is a 4 bit field M[3:0] in the ARMARM, we split it into parts.
271 cpsr_fields.push_back({"EL", 2, 3});
272 // Bit 1 is unused and expected to be 0.
273 cpsr_fields.push_back({"SP", 0});
274
275 return cpsr_fields;
276}
277
278void Arm64RegisterFlagsDetector::DetectFields(uint64_t hwcap, uint64_t hwcap2,
279 uint64_t hwcap3) {
280 for (auto &reg : m_registers)
281 reg.m_flags.SetFields(reg.m_detector(hwcap, hwcap2, hwcap3));
282 m_has_detected = true;
283}
284
286 const RegisterInfo *reg_info, uint32_t num_regs) {
287 assert(m_has_detected &&
288 "Must call DetectFields before updating register info.");
289
290 // Register names will not be duplicated, so we do not want to compare against
291 // one if it has already been found. Each time we find one, we erase it from
292 // this list.
293 std::vector<std::pair<llvm::StringRef, const RegisterFlags *>>
294 search_registers;
295 for (const auto &reg : m_registers) {
296 // It is possible that a register is all extension dependent fields, and
297 // none of them are present.
298 if (reg.m_flags.GetFields().size())
299 search_registers.push_back({reg.m_name, &reg.m_flags});
300 }
301
302 // Walk register information while there are registers we know need
303 // to be updated. Example:
304 // Register information: [a, b, c, d]
305 // To be patched: [b, c]
306 // * a != b, a != c, do nothing and move on.
307 // * b == b, patch b, new patch list is [c], move on.
308 // * c == c, patch c, patch list is empty, exit early without looking at d.
309 for (uint32_t idx = 0; idx < num_regs && search_registers.size();
310 ++idx, ++reg_info) {
311 auto reg_it = std::find_if(
312 search_registers.cbegin(), search_registers.cend(),
313 [reg_info](auto reg) { return reg.first == reg_info->name; });
314
315 if (reg_it != search_registers.end()) {
316 // Attach the field information.
317 reg_info->flags_type = reg_it->second;
318 // We do not expect to see this name again so don't look for it again.
319 search_registers.erase(reg_it);
320 }
321 }
322
323 // We do not assert that search_registers is empty here, because it may
324 // contain registers from optional extensions that are not present on the
325 // current target.
326}
#define HWCAP2_MTE
#define HWCAP3_MTE_STORE_ONLY
#define HWCAP_ASIMDHP
#define HWCAP2_FPMR
#define HWCAP2_EBF16
static Fields DetectFPCRFields(uint64_t hwcap, uint64_t hwcap2, uint64_t hwcap3)
void DetectFields(uint64_t hwcap, uint64_t hwcap2, uint64_t hwcap3)
For the registers listed in this class, detect which fields are present.
void UpdateRegisterInfo(const RegisterInfo *reg_info, uint32_t num_regs)
Add the field information of any registers named in this class, to the relevant RegisterInfo instance...
struct lldb_private::Arm64RegisterFlagsDetector::RegisterEntry m_registers[9]
static Fields DetectSVCRFields(uint64_t hwcap, uint64_t hwcap2, uint64_t hwcap3)
static Fields DetectFPMRFields(uint64_t hwcap, uint64_t hwcap2, uint64_t hwcap3)
static Fields DetectFPSRFields(uint64_t hwcap, uint64_t hwcap2, uint64_t hwcap3)
static Fields DetectMTECtrlFields(uint64_t hwcap, uint64_t hwcap2, uint64_t hwcap3)
static Fields DetectGCSFeatureFields(uint64_t hwcap, uint64_t hwcap2, uint64_t hwcap3)
static Fields DetectCPSRFields(uint64_t hwcap, uint64_t hwcap2, uint64_t hwcap3)
static Fields DetectPOREL0Fields(uint64_t hwcap, uint64_t hwcap2, uint64_t hwcap3)
A class that represents a running process on the host machine.
Every register is described in detail including its name, alternate name (optional),...
const RegisterFlags * flags_type
If not nullptr, a type defined by XML descriptions.