1*c9157d92SDimitry Andric //===-- RegisterFlagsLinux_arm64.cpp --------------------------------------===//
2*c9157d92SDimitry Andric //
3*c9157d92SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*c9157d92SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*c9157d92SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*c9157d92SDimitry Andric //
7*c9157d92SDimitry Andric //===----------------------------------------------------------------------===//
8*c9157d92SDimitry Andric
9*c9157d92SDimitry Andric #include "RegisterFlagsLinux_arm64.h"
10*c9157d92SDimitry Andric #include "lldb/lldb-private-types.h"
11*c9157d92SDimitry Andric
12*c9157d92SDimitry Andric // This file is built on all systems because it is used by native processes and
13*c9157d92SDimitry Andric // core files, so we manually define the needed HWCAP values here.
14*c9157d92SDimitry Andric
15*c9157d92SDimitry Andric #define HWCAP_FPHP (1ULL << 9)
16*c9157d92SDimitry Andric #define HWCAP_ASIMDHP (1ULL << 10)
17*c9157d92SDimitry Andric #define HWCAP_DIT (1ULL << 24)
18*c9157d92SDimitry Andric #define HWCAP_SSBS (1ULL << 28)
19*c9157d92SDimitry Andric
20*c9157d92SDimitry Andric #define HWCAP2_BTI (1ULL << 17)
21*c9157d92SDimitry Andric #define HWCAP2_MTE (1ULL << 18)
22*c9157d92SDimitry Andric #define HWCAP2_AFP (1ULL << 20)
23*c9157d92SDimitry Andric #define HWCAP2_EBF16 (1ULL << 32)
24*c9157d92SDimitry Andric
25*c9157d92SDimitry Andric using namespace lldb_private;
26*c9157d92SDimitry Andric
27*c9157d92SDimitry Andric LinuxArm64RegisterFlags::Fields
DetectSVCRFields(uint64_t hwcap,uint64_t hwcap2)28*c9157d92SDimitry Andric LinuxArm64RegisterFlags::DetectSVCRFields(uint64_t hwcap, uint64_t hwcap2) {
29*c9157d92SDimitry Andric (void)hwcap;
30*c9157d92SDimitry Andric (void)hwcap2;
31*c9157d92SDimitry Andric // Represents the pseudo register that lldb-server builds, which itself
32*c9157d92SDimitry Andric // matches the architectural register SCVR. The fields match SVCR in the Arm
33*c9157d92SDimitry Andric // manual.
34*c9157d92SDimitry Andric return {
35*c9157d92SDimitry Andric {"ZA", 1},
36*c9157d92SDimitry Andric {"SM", 0},
37*c9157d92SDimitry Andric };
38*c9157d92SDimitry Andric }
39*c9157d92SDimitry Andric
40*c9157d92SDimitry Andric LinuxArm64RegisterFlags::Fields
DetectMTECtrlFields(uint64_t hwcap,uint64_t hwcap2)41*c9157d92SDimitry Andric LinuxArm64RegisterFlags::DetectMTECtrlFields(uint64_t hwcap, uint64_t hwcap2) {
42*c9157d92SDimitry Andric (void)hwcap;
43*c9157d92SDimitry Andric (void)hwcap2;
44*c9157d92SDimitry Andric // Represents the contents of NT_ARM_TAGGED_ADDR_CTRL and the value passed
45*c9157d92SDimitry Andric // to prctl(PR_TAGGED_ADDR_CTRL...). Fields are derived from the defines
46*c9157d92SDimitry Andric // used to build the value.
47*c9157d92SDimitry Andric return {{"TAGS", 3, 18}, // 16 bit bitfield shifted up by PR_MTE_TAG_SHIFT.
48*c9157d92SDimitry Andric {"TCF_ASYNC", 2},
49*c9157d92SDimitry Andric {"TCF_SYNC", 1},
50*c9157d92SDimitry Andric {"TAGGED_ADDR_ENABLE", 0}};
51*c9157d92SDimitry Andric }
52*c9157d92SDimitry Andric
53*c9157d92SDimitry Andric LinuxArm64RegisterFlags::Fields
DetectFPCRFields(uint64_t hwcap,uint64_t hwcap2)54*c9157d92SDimitry Andric LinuxArm64RegisterFlags::DetectFPCRFields(uint64_t hwcap, uint64_t hwcap2) {
55*c9157d92SDimitry Andric std::vector<RegisterFlags::Field> fpcr_fields{
56*c9157d92SDimitry Andric {"AHP", 26}, {"DN", 25}, {"FZ", 24}, {"RMode", 22, 23},
57*c9157d92SDimitry Andric // Bits 21-20 are "Stride" which is unused in AArch64 state.
58*c9157d92SDimitry Andric };
59*c9157d92SDimitry Andric
60*c9157d92SDimitry Andric // FEAT_FP16 is indicated by the presence of FPHP (floating point half
61*c9157d92SDimitry Andric // precision) and ASIMDHP (Advanced SIMD half precision) features.
62*c9157d92SDimitry Andric if ((hwcap & HWCAP_FPHP) && (hwcap & HWCAP_ASIMDHP))
63*c9157d92SDimitry Andric fpcr_fields.push_back({"FZ16", 19});
64*c9157d92SDimitry Andric
65*c9157d92SDimitry Andric // Bits 18-16 are "Len" which is unused in AArch64 state.
66*c9157d92SDimitry Andric
67*c9157d92SDimitry Andric fpcr_fields.push_back({"IDE", 15});
68*c9157d92SDimitry Andric
69*c9157d92SDimitry Andric // Bit 14 is unused.
70*c9157d92SDimitry Andric if (hwcap2 & HWCAP2_EBF16)
71*c9157d92SDimitry Andric fpcr_fields.push_back({"EBF", 13});
72*c9157d92SDimitry Andric
73*c9157d92SDimitry Andric fpcr_fields.push_back({"IXE", 12});
74*c9157d92SDimitry Andric fpcr_fields.push_back({"UFE", 11});
75*c9157d92SDimitry Andric fpcr_fields.push_back({"OFE", 10});
76*c9157d92SDimitry Andric fpcr_fields.push_back({"DZE", 9});
77*c9157d92SDimitry Andric fpcr_fields.push_back({"IOE", 8});
78*c9157d92SDimitry Andric // Bits 7-3 reserved.
79*c9157d92SDimitry Andric
80*c9157d92SDimitry Andric if (hwcap2 & HWCAP2_AFP) {
81*c9157d92SDimitry Andric fpcr_fields.push_back({"NEP", 2});
82*c9157d92SDimitry Andric fpcr_fields.push_back({"AH", 1});
83*c9157d92SDimitry Andric fpcr_fields.push_back({"FIZ", 0});
84*c9157d92SDimitry Andric }
85*c9157d92SDimitry Andric
86*c9157d92SDimitry Andric return fpcr_fields;
87*c9157d92SDimitry Andric }
88*c9157d92SDimitry Andric
89*c9157d92SDimitry Andric LinuxArm64RegisterFlags::Fields
DetectFPSRFields(uint64_t hwcap,uint64_t hwcap2)90*c9157d92SDimitry Andric LinuxArm64RegisterFlags::DetectFPSRFields(uint64_t hwcap, uint64_t hwcap2) {
91*c9157d92SDimitry Andric // fpsr's contents are constant.
92*c9157d92SDimitry Andric (void)hwcap;
93*c9157d92SDimitry Andric (void)hwcap2;
94*c9157d92SDimitry Andric
95*c9157d92SDimitry Andric return {
96*c9157d92SDimitry Andric // Bits 31-28 are N/Z/C/V, only used by AArch32.
97*c9157d92SDimitry Andric {"QC", 27},
98*c9157d92SDimitry Andric // Bits 26-8 reserved.
99*c9157d92SDimitry Andric {"IDC", 7},
100*c9157d92SDimitry Andric // Bits 6-5 reserved.
101*c9157d92SDimitry Andric {"IXC", 4},
102*c9157d92SDimitry Andric {"UFC", 3},
103*c9157d92SDimitry Andric {"OFC", 2},
104*c9157d92SDimitry Andric {"DZC", 1},
105*c9157d92SDimitry Andric {"IOC", 0},
106*c9157d92SDimitry Andric };
107*c9157d92SDimitry Andric }
108*c9157d92SDimitry Andric
109*c9157d92SDimitry Andric LinuxArm64RegisterFlags::Fields
DetectCPSRFields(uint64_t hwcap,uint64_t hwcap2)110*c9157d92SDimitry Andric LinuxArm64RegisterFlags::DetectCPSRFields(uint64_t hwcap, uint64_t hwcap2) {
111*c9157d92SDimitry Andric // The fields here are a combination of the Arm manual's SPSR_EL1,
112*c9157d92SDimitry Andric // plus a few changes where Linux has decided not to make use of them at all,
113*c9157d92SDimitry Andric // or at least not from userspace.
114*c9157d92SDimitry Andric
115*c9157d92SDimitry Andric // Status bits that are always present.
116*c9157d92SDimitry Andric std::vector<RegisterFlags::Field> cpsr_fields{
117*c9157d92SDimitry Andric {"N", 31}, {"Z", 30}, {"C", 29}, {"V", 28},
118*c9157d92SDimitry Andric // Bits 27-26 reserved.
119*c9157d92SDimitry Andric };
120*c9157d92SDimitry Andric
121*c9157d92SDimitry Andric if (hwcap2 & HWCAP2_MTE)
122*c9157d92SDimitry Andric cpsr_fields.push_back({"TCO", 25});
123*c9157d92SDimitry Andric if (hwcap & HWCAP_DIT)
124*c9157d92SDimitry Andric cpsr_fields.push_back({"DIT", 24});
125*c9157d92SDimitry Andric
126*c9157d92SDimitry Andric // UAO and PAN are bits 23 and 22 and have no meaning for userspace so
127*c9157d92SDimitry Andric // are treated as reserved by the kernel.
128*c9157d92SDimitry Andric
129*c9157d92SDimitry Andric cpsr_fields.push_back({"SS", 21});
130*c9157d92SDimitry Andric cpsr_fields.push_back({"IL", 20});
131*c9157d92SDimitry Andric // Bits 19-14 reserved.
132*c9157d92SDimitry Andric
133*c9157d92SDimitry Andric // Bit 13, ALLINT, requires FEAT_NMI that isn't relevant to userspace, and we
134*c9157d92SDimitry Andric // can't detect either, don't show this field.
135*c9157d92SDimitry Andric if (hwcap & HWCAP_SSBS)
136*c9157d92SDimitry Andric cpsr_fields.push_back({"SSBS", 12});
137*c9157d92SDimitry Andric if (hwcap2 & HWCAP2_BTI)
138*c9157d92SDimitry Andric cpsr_fields.push_back({"BTYPE", 10, 11});
139*c9157d92SDimitry Andric
140*c9157d92SDimitry Andric cpsr_fields.push_back({"D", 9});
141*c9157d92SDimitry Andric cpsr_fields.push_back({"A", 8});
142*c9157d92SDimitry Andric cpsr_fields.push_back({"I", 7});
143*c9157d92SDimitry Andric cpsr_fields.push_back({"F", 6});
144*c9157d92SDimitry Andric // Bit 5 reserved
145*c9157d92SDimitry Andric // Called "M" in the ARMARM.
146*c9157d92SDimitry Andric cpsr_fields.push_back({"nRW", 4});
147*c9157d92SDimitry Andric // This is a 4 bit field M[3:0] in the ARMARM, we split it into parts.
148*c9157d92SDimitry Andric cpsr_fields.push_back({"EL", 2, 3});
149*c9157d92SDimitry Andric // Bit 1 is unused and expected to be 0.
150*c9157d92SDimitry Andric cpsr_fields.push_back({"SP", 0});
151*c9157d92SDimitry Andric
152*c9157d92SDimitry Andric return cpsr_fields;
153*c9157d92SDimitry Andric }
154*c9157d92SDimitry Andric
DetectFields(uint64_t hwcap,uint64_t hwcap2)155*c9157d92SDimitry Andric void LinuxArm64RegisterFlags::DetectFields(uint64_t hwcap, uint64_t hwcap2) {
156*c9157d92SDimitry Andric for (auto ® : m_registers)
157*c9157d92SDimitry Andric reg.m_flags.SetFields(reg.m_detector(hwcap, hwcap2));
158*c9157d92SDimitry Andric m_has_detected = true;
159*c9157d92SDimitry Andric }
160*c9157d92SDimitry Andric
UpdateRegisterInfo(const RegisterInfo * reg_info,uint32_t num_regs)161*c9157d92SDimitry Andric void LinuxArm64RegisterFlags::UpdateRegisterInfo(const RegisterInfo *reg_info,
162*c9157d92SDimitry Andric uint32_t num_regs) {
163*c9157d92SDimitry Andric assert(m_has_detected &&
164*c9157d92SDimitry Andric "Must call DetectFields before updating register info.");
165*c9157d92SDimitry Andric
166*c9157d92SDimitry Andric // Register names will not be duplicated, so we do not want to compare against
167*c9157d92SDimitry Andric // one if it has already been found. Each time we find one, we erase it from
168*c9157d92SDimitry Andric // this list.
169*c9157d92SDimitry Andric std::vector<std::pair<llvm::StringRef, const RegisterFlags *>>
170*c9157d92SDimitry Andric search_registers;
171*c9157d92SDimitry Andric for (const auto ® : m_registers) {
172*c9157d92SDimitry Andric // It is possible that a register is all extension dependent fields, and
173*c9157d92SDimitry Andric // none of them are present.
174*c9157d92SDimitry Andric if (reg.m_flags.GetFields().size())
175*c9157d92SDimitry Andric search_registers.push_back({reg.m_name, ®.m_flags});
176*c9157d92SDimitry Andric }
177*c9157d92SDimitry Andric
178*c9157d92SDimitry Andric // Walk register information while there are registers we know need
179*c9157d92SDimitry Andric // to be updated. Example:
180*c9157d92SDimitry Andric // Register information: [a, b, c, d]
181*c9157d92SDimitry Andric // To be patched: [b, c]
182*c9157d92SDimitry Andric // * a != b, a != c, do nothing and move on.
183*c9157d92SDimitry Andric // * b == b, patch b, new patch list is [c], move on.
184*c9157d92SDimitry Andric // * c == c, patch c, patch list is empty, exit early without looking at d.
185*c9157d92SDimitry Andric for (uint32_t idx = 0; idx < num_regs && search_registers.size();
186*c9157d92SDimitry Andric ++idx, ++reg_info) {
187*c9157d92SDimitry Andric auto reg_it = std::find_if(
188*c9157d92SDimitry Andric search_registers.cbegin(), search_registers.cend(),
189*c9157d92SDimitry Andric [reg_info](auto reg) { return reg.first == reg_info->name; });
190*c9157d92SDimitry Andric
191*c9157d92SDimitry Andric if (reg_it != search_registers.end()) {
192*c9157d92SDimitry Andric // Attach the field information.
193*c9157d92SDimitry Andric reg_info->flags_type = reg_it->second;
194*c9157d92SDimitry Andric // We do not expect to see this name again so don't look for it again.
195*c9157d92SDimitry Andric search_registers.erase(reg_it);
196*c9157d92SDimitry Andric }
197*c9157d92SDimitry Andric }
198*c9157d92SDimitry Andric
199*c9157d92SDimitry Andric // We do not assert that search_registers is empty here, because it may
200*c9157d92SDimitry Andric // contain registers from optional extensions that are not present on the
201*c9157d92SDimitry Andric // current target.
202*c9157d92SDimitry Andric }