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
29#define HWCAP3_MTE_STORE_ONLY (1ULL << 1)
30
31using namespace lldb_private;
32
34Arm64RegisterFlagsDetector::DetectFPMRFields(uint64_t hwcap, uint64_t hwcap2,
35 uint64_t hwcap3) {
36 (void)hwcap;
37 (void)hwcap3;
38
39 if (!(hwcap2 & HWCAP2_FPMR))
40 return {};
41
42 static const FieldEnum fp8_format_enum("fp8_format_enum", {
43 {0, "FP8_E5M2"},
44 {1, "FP8_E4M3"},
45 });
46 return {
47 {"LSCALE2", 32, 37},
48 {"NSCALE", 24, 31},
49 {"LSCALE", 16, 22},
50 {"OSC", 15},
51 {"OSM", 14},
52 {"F8D", 6, 8, &fp8_format_enum},
53 {"F8S2", 3, 5, &fp8_format_enum},
54 {"F8S1", 0, 2, &fp8_format_enum},
55 };
56}
57
60 uint64_t hwcap2,
61 uint64_t hwcap3) {
62 (void)hwcap2;
63 (void)hwcap3;
64
65 if (!(hwcap & HWCAP_GCS))
66 return {};
67
68 return {
69 {"PUSH", 2},
70 {"WRITE", 1},
71 {"ENABLE", 0},
72 };
73}
74
76Arm64RegisterFlagsDetector::DetectSVCRFields(uint64_t hwcap, uint64_t hwcap2,
77 uint64_t hwcap3) {
78 (void)hwcap;
79 (void)hwcap3;
80
81 if (!(hwcap2 & HWCAP2_SME))
82 return {};
83
84 // Represents the pseudo register that lldb-server builds, which itself
85 // matches the architectural register SCVR. The fields match SVCR in the Arm
86 // manual.
87 return {
88 {"ZA", 1},
89 {"SM", 0},
90 };
91}
92
95 uint64_t hwcap3) {
96 (void)hwcap;
97
98 if (!(hwcap2 & HWCAP2_MTE))
99 return {};
100
101 // Represents the contents of NT_ARM_TAGGED_ADDR_CTRL and the value passed
102 // to prctl(PR_TAGGED_ADDR_CTRL...). Fields are derived from the defines
103 // used to build the value.
104
105 std::vector<RegisterFlags::Field> fields;
106 fields.reserve(4);
107 if (hwcap3 & HWCAP3_MTE_STORE_ONLY)
108 fields.push_back({"STORE_ONLY", 19});
109
110 static const FieldEnum tcf_enum(
111 "tcf_enum",
112 {{0, "TCF_NONE"}, {1, "TCF_SYNC"}, {2, "TCF_ASYNC"}, {3, "TCF_ASYMM"}});
113
114 fields.insert(
115 std::end(fields),
116 {{"TAGS", 3, 18}, // 16 bit bitfield shifted up by PR_MTE_TAG_SHIFT.
117 {"TCF", 1, 2, &tcf_enum},
118 {"TAGGED_ADDR_ENABLE", 0}});
119
120 return fields;
121}
122
124Arm64RegisterFlagsDetector::DetectFPCRFields(uint64_t hwcap, uint64_t hwcap2,
125 uint64_t hwcap3) {
126 (void)hwcap3;
127
128 static const FieldEnum rmode_enum(
129 "rmode_enum", {{0, "RN"}, {1, "RP"}, {2, "RM"}, {3, "RZ"}});
130
131 std::vector<RegisterFlags::Field> fpcr_fields{
132 {"AHP", 26}, {"DN", 25}, {"FZ", 24}, {"RMode", 22, 23, &rmode_enum},
133 // Bits 21-20 are "Stride" which is unused in AArch64 state.
134 };
135
136 // FEAT_FP16 is indicated by the presence of FPHP (floating point half
137 // precision) and ASIMDHP (Advanced SIMD half precision) features.
138 if ((hwcap & HWCAP_FPHP) && (hwcap & HWCAP_ASIMDHP))
139 fpcr_fields.push_back({"FZ16", 19});
140
141 // Bits 18-16 are "Len" which is unused in AArch64 state.
142
143 fpcr_fields.push_back({"IDE", 15});
144
145 // Bit 14 is unused.
146 if (hwcap2 & HWCAP2_EBF16)
147 fpcr_fields.push_back({"EBF", 13});
148
149 fpcr_fields.push_back({"IXE", 12});
150 fpcr_fields.push_back({"UFE", 11});
151 fpcr_fields.push_back({"OFE", 10});
152 fpcr_fields.push_back({"DZE", 9});
153 fpcr_fields.push_back({"IOE", 8});
154 // Bits 7-3 reserved.
155
156 if (hwcap2 & HWCAP2_AFP) {
157 fpcr_fields.push_back({"NEP", 2});
158 fpcr_fields.push_back({"AH", 1});
159 fpcr_fields.push_back({"FIZ", 0});
160 }
161
162 return fpcr_fields;
163}
164
166Arm64RegisterFlagsDetector::DetectFPSRFields(uint64_t hwcap, uint64_t hwcap2,
167 uint64_t hwcap3) {
168 // fpsr's contents are constant.
169 (void)hwcap;
170 (void)hwcap2;
171 (void)hwcap3;
172
173 return {
174 // Bits 31-28 are N/Z/C/V, only used by AArch32.
175 {"QC", 27},
176 // Bits 26-8 reserved.
177 {"IDC", 7},
178 // Bits 6-5 reserved.
179 {"IXC", 4},
180 {"UFC", 3},
181 {"OFC", 2},
182 {"DZC", 1},
183 {"IOC", 0},
184 };
185}
186
188Arm64RegisterFlagsDetector::DetectCPSRFields(uint64_t hwcap, uint64_t hwcap2,
189 uint64_t hwcap3) {
190 (void)hwcap3;
191
192 // The fields here are a combination of the Arm manual's SPSR_EL1,
193 // plus a few changes where Linux has decided not to make use of them at all,
194 // or at least not from userspace.
195
196 // Status bits that are always present.
197 std::vector<RegisterFlags::Field> cpsr_fields{
198 {"N", 31}, {"Z", 30}, {"C", 29}, {"V", 28},
199 // Bits 27-26 reserved.
200 };
201
202 if (hwcap2 & HWCAP2_MTE)
203 cpsr_fields.push_back({"TCO", 25});
204 if (hwcap & HWCAP_DIT)
205 cpsr_fields.push_back({"DIT", 24});
206
207 // UAO and PAN are bits 23 and 22 and have no meaning for userspace so
208 // are treated as reserved by the kernels.
209
210 cpsr_fields.push_back({"SS", 21});
211 cpsr_fields.push_back({"IL", 20});
212 // Bits 19-14 reserved.
213
214 // Bit 13, ALLINT, requires FEAT_NMI that isn't relevant to userspace, and we
215 // can't detect either, don't show this field.
216 if (hwcap & HWCAP_SSBS)
217 cpsr_fields.push_back({"SSBS", 12});
218 if (hwcap2 & HWCAP2_BTI)
219 cpsr_fields.push_back({"BTYPE", 10, 11});
220
221 cpsr_fields.push_back({"D", 9});
222 cpsr_fields.push_back({"A", 8});
223 cpsr_fields.push_back({"I", 7});
224 cpsr_fields.push_back({"F", 6});
225 // Bit 5 reserved
226 // Called "M" in the ARMARM.
227 cpsr_fields.push_back({"nRW", 4});
228 // This is a 4 bit field M[3:0] in the ARMARM, we split it into parts.
229 cpsr_fields.push_back({"EL", 2, 3});
230 // Bit 1 is unused and expected to be 0.
231 cpsr_fields.push_back({"SP", 0});
232
233 return cpsr_fields;
234}
235
236void Arm64RegisterFlagsDetector::DetectFields(uint64_t hwcap, uint64_t hwcap2,
237 uint64_t hwcap3) {
238 for (auto &reg : m_registers)
239 reg.m_flags.SetFields(reg.m_detector(hwcap, hwcap2, hwcap3));
240 m_has_detected = true;
241}
242
244 const RegisterInfo *reg_info, uint32_t num_regs) {
245 assert(m_has_detected &&
246 "Must call DetectFields before updating register info.");
247
248 // Register names will not be duplicated, so we do not want to compare against
249 // one if it has already been found. Each time we find one, we erase it from
250 // this list.
251 std::vector<std::pair<llvm::StringRef, const RegisterFlags *>>
252 search_registers;
253 for (const auto &reg : m_registers) {
254 // It is possible that a register is all extension dependent fields, and
255 // none of them are present.
256 if (reg.m_flags.GetFields().size())
257 search_registers.push_back({reg.m_name, &reg.m_flags});
258 }
259
260 // Walk register information while there are registers we know need
261 // to be updated. Example:
262 // Register information: [a, b, c, d]
263 // To be patched: [b, c]
264 // * a != b, a != c, do nothing and move on.
265 // * b == b, patch b, new patch list is [c], move on.
266 // * c == c, patch c, patch list is empty, exit early without looking at d.
267 for (uint32_t idx = 0; idx < num_regs && search_registers.size();
268 ++idx, ++reg_info) {
269 auto reg_it = std::find_if(
270 search_registers.cbegin(), search_registers.cend(),
271 [reg_info](auto reg) { return reg.first == reg_info->name; });
272
273 if (reg_it != search_registers.end()) {
274 // Attach the field information.
275 reg_info->flags_type = reg_it->second;
276 // We do not expect to see this name again so don't look for it again.
277 search_registers.erase(reg_it);
278 }
279 }
280
281 // We do not assert that search_registers is empty here, because it may
282 // contain registers from optional extensions that are not present on the
283 // current target.
284}
#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...
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)
struct lldb_private::Arm64RegisterFlagsDetector::RegisterEntry m_registers[8]
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)
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.