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