brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.9 KiB · 330a24a Raw
285 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "RegisterFlagsDetector_arm64.h"10#include "lldb/lldb-private-types.h"11 12// This file is built on all systems because it is used by native processes and13// 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 33Arm64RegisterFlagsDetector::Fields34Arm64RegisterFlagsDetector::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 58Arm64RegisterFlagsDetector::Fields59Arm64RegisterFlagsDetector::DetectGCSFeatureFields(uint64_t hwcap,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 75Arm64RegisterFlagsDetector::Fields76Arm64RegisterFlagsDetector::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 itself85  // matches the architectural register SCVR. The fields match SVCR in the Arm86  // manual.87  return {88      {"ZA", 1},89      {"SM", 0},90  };91}92 93Arm64RegisterFlagsDetector::Fields94Arm64RegisterFlagsDetector::DetectMTECtrlFields(uint64_t hwcap, uint64_t hwcap2,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 passed102  // to prctl(PR_TAGGED_ADDR_CTRL...). Fields are derived from the defines103  // 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 123Arm64RegisterFlagsDetector::Fields124Arm64RegisterFlagsDetector::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 half137  // 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 165Arm64RegisterFlagsDetector::Fields166Arm64RegisterFlagsDetector::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 187Arm64RegisterFlagsDetector::Fields188Arm64RegisterFlagsDetector::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 so208  // 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 we215  // 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 reserved226  // 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 243void Arm64RegisterFlagsDetector::UpdateRegisterInfo(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 against249  // one if it has already been found. Each time we find one, we erase it from250  // 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, and255    // 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 need261  // 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 may282  // contain registers from optional extensions that are not present on the283  // current target.284}285