Files
Ryan Houdek 0ec724cf1f HostFeatures: Moves MIDR querying to the frontend
The MIDR querying is inherently OS specific and needs a bit of special
casing. Instead let the frontend inform FEXCore how many CPU cores there
are and their MIDRs instead.

This lets us keep the Linux specific code in the frontend.
2024-08-23 00:53:53 -07:00

631 lines
13 KiB
C++

// SPDX-License-Identifier: MIT
#pragma once
#include <FEXCore/Core/HostFeatures.h>
#include <FEXCore/Utils/EnumUtils.h>
#include <cstddef>
namespace FEX {
class CPUFeatures {
public:
enum class Feature : uint32_t {
// ISAR0
AES,
PMULL,
SHA1,
SHA2,
SHA512,
CRC32,
LSE,
LSE128,
TME,
RDM,
SHA3,
SM3,
SM4,
DotProd,
FlagM,
FlagM2,
RNDR,
// PFR0
FP,
FP16,
ASIMD,
ASIMD16,
RAS,
SVE,
DIT,
CSV2,
CSV3,
// PFR1
BTI,
SSBS,
SSBS2,
MTE,
MTE2,
MTE3,
SME,
SME2,
// ISAR1
DPB,
DPB2,
JSCVT,
FCMA,
LRCPC,
LRCPC2,
LRCPC3,
FRINTTS,
SB,
SPECRES,
SPECRES2,
BF16,
SME_F64F64,
I8MM,
XS,
LS64,
LS64_V,
LS64_ACCDATA,
// MMFR0
ECV,
// MMFR2
LSE2,
// ZFR0
SVE2,
SVE2_1,
SVE_AES,
SVE_PMULL128,
SVE_BitPerm,
SVE_BF16,
SVE_B16B16,
SVE_SHA3,
SVE_SM4,
SVE_I8MM,
SVE_F32MM,
SVE_F64MM,
// MMFR1
AFP,
// ISAR2
WFxt,
RPRES,
PACQARMA3,
MOPS,
HBC,
CLRBHB,
SYSREG128,
SYSINSTR128,
PRFMSLC,
RPRFM,
CSSC,
// Max indicator
MAX,
};
static_assert(FEXCore::ToUnderlying(Feature::MAX) < 128);
static_assert((FEXCore::ToUnderlying(Feature::MAX) / (sizeof(uint64_t) * 8)) == 1);
bool Supports(Feature feat) const {
const size_t DWordSelect = FEXCore::ToUnderlying(feat) / (sizeof(uint64_t) * 8);
const size_t BitSelect = FEXCore::ToUnderlying(feat) - (DWordSelect * (sizeof(uint64_t) * 8));
return (FeatureBits[DWordSelect] >> BitSelect) & 1;
}
void RemoveFeature(Feature feat) {
const size_t DWordSelect = FEXCore::ToUnderlying(feat) / (sizeof(uint64_t) * 8);
const size_t BitSelect = FEXCore::ToUnderlying(feat) - (DWordSelect * (sizeof(uint64_t) * 8));
FeatureBits[DWordSelect] &= ~(1ULL << BitSelect);
}
protected:
void FillFeatureFlags();
// This list is informed by Linux kernel's `Documentation/arch/arm64/cpu-feature-registers.rst`
enum class FeatureRegType {
ISAR0_EL1,
PFR0_EL1,
PFR1_EL1,
MIDR_EL1,
ISAR1_EL1,
MMFR0_EL1,
MMFR2_EL1,
ZFR0_EL1,
MMFR1_EL1,
ISAR2_EL1,
};
class FeatureReg {
public:
void SetReg(uint64_t _Reg) {
Reg = _Reg;
}
protected:
// All feature flag fields are 4-bits.
uint64_t GetField(uint64_t Offset) const {
return (Reg >> Offset) & 0b1111;
}
uint64_t Reg {};
};
#define FIELD_FETCHER(feature, field, minimum_field) \
bool Supports##feature() const { \
return GetField(field) >= minimum_field; \
}
class ISAR0Reg final : public FeatureReg {
public:
FIELD_FETCHER(AES, AES, 0b0001);
FIELD_FETCHER(PMULL, AES, 0b0010);
FIELD_FETCHER(SHA1, SHA1, 0b0001);
FIELD_FETCHER(SHA2, SHA2, 0b0001);
FIELD_FETCHER(SHA512, SHA2, 0b0010);
FIELD_FETCHER(CRC32, CRC32, 0b0001);
FIELD_FETCHER(LSE, Atomic, 0b0010);
FIELD_FETCHER(LSE128, Atomic, 0b0011);
FIELD_FETCHER(TME, TME, 0b0001);
FIELD_FETCHER(RDM, RDM, 0b0001);
FIELD_FETCHER(SHA3, SHA3, 0b0001);
FIELD_FETCHER(SM3, SM3, 0b0001);
FIELD_FETCHER(SM4, SM4, 0b0001);
FIELD_FETCHER(DotProd, DP, 0b0001);
FIELD_FETCHER(FHM, FHM, 0b0001);
FIELD_FETCHER(FlagM, TS, 0b0001);
FIELD_FETCHER(FlagM2, TS, 0b0010);
FIELD_FETCHER(TLBIOS, TLB, 0b0001);
FIELD_FETCHER(TLBIRANGE, TLB, 0b0010);
FIELD_FETCHER(RNDR, RNDR, 0b0001);
private:
enum Field {
RES0 = 0 * 4,
AES = 1 * 4,
SHA1 = 2 * 4,
SHA2 = 3 * 4,
CRC32 = 4 * 4,
Atomic = 5 * 4,
TME = 6 * 4,
RDM = 7 * 4,
SHA3 = 8 * 4,
SM3 = 9 * 4,
SM4 = 10 * 4,
DP = 11 * 4,
FHM = 12 * 4,
TS = 13 * 4,
TLB = 14 * 4,
RNDR = 15 * 4,
};
};
class PFR0Reg final : public FeatureReg {
public:
FIELD_FETCHER(AA64_EL0, EL0, 0b0001);
FIELD_FETCHER(AA32_EL0, EL0, 0b0010);
FIELD_FETCHER(AA64_EL1, EL1, 0b0001);
FIELD_FETCHER(AA32_EL1, EL1, 0b0010);
FIELD_FETCHER(AA64_EL2, EL2, 0b0001);
FIELD_FETCHER(AA32_EL2, EL2, 0b0010);
FIELD_FETCHER(AA64_EL3, EL3, 0b0001);
FIELD_FETCHER(AA32_EL3, EL3, 0b0010);
bool SupportsFP() const {
return GetField(FP) != 0b1111;
}
FIELD_FETCHER(HP, FP, 0b0001);
bool SupportsAdvSIMD() const {
return GetField(AdvSIMD) != 0b1111;
}
FIELD_FETCHER(ASIMDHP, AdvSIMD, 0b0001);
FIELD_FETCHER(GIC4_0, GIC, 0b0001);
FIELD_FETCHER(GIC4_1, GIC, 0b0011);
FIELD_FETCHER(RAS, RAS, 0b0001);
FIELD_FETCHER(RAS1_1, RAS, 0b0010);
FIELD_FETCHER(RAS2, RAS, 0b0011);
FIELD_FETCHER(SVE, SVE, 0b0001);
FIELD_FETCHER(SEL2, SEL2, 0b0001);
uint64_t MPAM_Major() const {
return GetField(MPAM);
}
FIELD_FETCHER(AMU1, AMU, 0b0001);
FIELD_FETCHER(AMU1_1, AMU, 0b0010);
FIELD_FETCHER(DIT, DIT, 0b0001);
FIELD_FETCHER(RME, RME, 0b0001);
FIELD_FETCHER(CSV2, CSV2, 0b0001);
FIELD_FETCHER(CSV2_2, CSV2, 0b0010);
FIELD_FETCHER(CSV2_3, CSV2, 0b0011);
FIELD_FETCHER(CSV3, CSV3, 0b0001);
private:
enum Field {
EL0 = 0 * 4,
EL1 = 1 * 4,
EL2 = 2 * 4,
EL3 = 3 * 4,
FP = 4 * 4,
AdvSIMD = 5 * 4,
GIC = 6 * 4,
RAS = 7 * 4,
SVE = 8 * 4,
SEL2 = 9 * 4,
MPAM = 10 * 4,
AMU = 11 * 4,
DIT = 12 * 4,
RME = 13 * 4,
CSV2 = 14 * 4,
CSV3 = 15 * 4,
};
};
class PFR1Reg final : public FeatureReg {
public:
FIELD_FETCHER(BTI, BT, 0b0001);
FIELD_FETCHER(SSBS, SSBS, 0b0001);
FIELD_FETCHER(SSBS2, SSBS, 0b0010);
FIELD_FETCHER(MTE, MTE, 0b0001);
FIELD_FETCHER(MTE2, MTE, 0b0010);
FIELD_FETCHER(MTE3, MTE, 0b0011);
uint64_t RAS_Minor() const {
return GetField(RAS_frac);
}
uint64_t MPAM_Minor() const {
return GetField(MPAM_frac);
}
FIELD_FETCHER(SME, SME, 0b0001);
FIELD_FETCHER(SME2, SME, 0b0010);
FIELD_FETCHER(RNDR_trap, RNDR_trap, 0b0001);
uint64_t CSV2_Minor() const {
return GetField(CSV2_frac);
}
FIELD_FETCHER(NMI, NMI, 0b0001);
uint64_t MTE_Minor() const {
return GetField(MTE_frac);
}
FIELD_FETCHER(GCS, GCS, 0b0001);
FIELD_FETCHER(THE, THE, 0b0001);
FIELD_FETCHER(MTEX, MTEX, 0b0001);
FIELD_FETCHER(DoubleFault2, DF2, 0b0001);
FIELD_FETCHER(PFAR, PFAR, 0b0001);
private:
enum Field {
BT = 0 * 4,
SSBS = 1 * 4,
MTE = 2 * 4,
RAS_frac = 3 * 4,
MPAM_frac = 4 * 4,
RES0 = 5 * 4,
SME = 6 * 4,
RNDR_trap = 7 * 4,
CSV2_frac = 8 * 4,
NMI = 9 * 4,
MTE_frac = 10 * 4,
GCS = 11 * 4,
THE = 12 * 4,
MTEX = 13 * 4,
DF2 = 14 * 4,
PFAR = 15 * 4,
};
};
class MIDRReg final : public FeatureReg {
public:
uint64_t GetRevision() const {
return GetField(Revision);
}
uint64_t GetPartNum() const {
return (Reg >> 4) & 0xFFF;
}
uint64_t GetArchitecture() const {
return GetField(Architecture);
}
uint64_t GetVariant() const {
return GetField(Variant);
}
uint64_t GetImplementer() const {
return (Reg >> 24) & 0xFFFF;
}
private:
enum Field {
Revision = 0 * 4,
// Partnum is 3 fields [15:4]
Architecture = 4 * 4,
Variant = 5 * 4,
// Implementer is 2 fields [31:24]
// Upper 32-bits is entirely reserved
};
};
class ISAR1Reg final : public FeatureReg {
public:
FIELD_FETCHER(DPB, DPB, 0b0001);
FIELD_FETCHER(DPB2, DPB, 0b0010);
// Ignoring APA and API
FIELD_FETCHER(JSCVT, JSCVT, 0b0001);
FIELD_FETCHER(FCMA, FCMA, 0b0001);
FIELD_FETCHER(LRCPC, LRCPC, 0b0001);
FIELD_FETCHER(LRCPC2, LRCPC, 0b0010);
FIELD_FETCHER(LRCPC3, LRCPC, 0b0011);
// Ignoring GPA and GPI
FIELD_FETCHER(FRINTTS, FRINTTS, 0b0001);
FIELD_FETCHER(SB, SB, 0b0001);
FIELD_FETCHER(SPECRES, SPECRES, 0b0001);
FIELD_FETCHER(SPECRES2, SPECRES, 0b0010);
FIELD_FETCHER(BF16, BF16, 0b0001);
FIELD_FETCHER(SME_F64F64, BF16, 0b0010);
FIELD_FETCHER(DGH, DGH, 0b0001);
FIELD_FETCHER(I8MM, I8MM, 0b0001);
FIELD_FETCHER(XS, XS, 0b0001);
FIELD_FETCHER(LS64, LS64, 0b0001);
FIELD_FETCHER(LS64_V, LS64, 0b0010);
FIELD_FETCHER(LS64_ACCDATA, LS64, 0b0011);
private:
enum Field {
DPB = 0 * 4,
APA = 1 * 4,
API = 2 * 4,
JSCVT = 3 * 4,
FCMA = 4 * 4,
LRCPC = 5 * 4,
GPA = 6 * 4,
GPI = 7 * 4,
FRINTTS = 8 * 4,
SB = 9 * 4,
SPECRES = 10 * 4,
BF16 = 11 * 4,
DGH = 12 * 4,
I8MM = 13 * 4,
XS = 14 * 4,
LS64 = 15 * 4,
};
};
class MMFR0Reg final : public FeatureReg {
public:
FIELD_FETCHER(ECV, ECV, 0b0010);
private:
enum Field {
PARange = 0 * 4,
ASIDBits = 1 * 4,
BigEnd = 2 * 4,
SNSMem = 3 * 4,
BigEndEL0 = 4 * 4,
TGran16 = 5 * 4,
TGran64 = 6 * 4,
TGran4 = 7 * 4,
TGran16_2 = 8 * 4,
TGran64_2 = 9 * 4,
TGran4_2 = 10 * 4,
ExS = 11 * 4,
RES0 = 12 * 4,
RES1 = 13 * 4,
FGT = 14 * 4,
ECV = 15 * 4,
};
};
class MMFR2Reg final : public FeatureReg {
public:
FIELD_FETCHER(LSE2, AT, 0b0001);
private:
enum Field {
CnP = 0 * 4,
UAO = 1 * 4,
LSM = 2 * 4,
IESB = 3 * 4,
VARange = 4 * 4,
CCIDX = 5 * 4,
NV = 6 * 4,
ST = 7 * 4,
AT = 8 * 4,
IDS = 9 * 4,
FWB = 10 * 4,
RES0 = 11 * 4,
TTL = 12 * 4,
BBM = 13 * 4,
EVT = 14 * 4,
E0PD = 15 * 4,
};
};
class ZFR0Reg final : public FeatureReg {
public:
FIELD_FETCHER(SVE2, SVEver, 0b0001);
FIELD_FETCHER(SVE2_1, SVEver, 0b0010);
FIELD_FETCHER(SVE_AES, AES, 0b0001);
FIELD_FETCHER(SVE_PMULL128, AES, 0b0010);
FIELD_FETCHER(SVE_BitPerm, BitPerm, 0b0001);
FIELD_FETCHER(SVE_BF16, BF16, 0b0001);
FIELD_FETCHER(SME_F64F64, BF16, 0b0010);
FIELD_FETCHER(SVE_B16B16, B16B16, 0b0010);
FIELD_FETCHER(SVE_SHA3, SHA3, 0b0001);
FIELD_FETCHER(SVE_SM4, SM4, 0b0001);
FIELD_FETCHER(SVE_I8MM, I8MM, 0b0001);
FIELD_FETCHER(SVE_F32MM, F32MM, 0b0001);
FIELD_FETCHER(SVE_F64MM, F64MM, 0b0001);
private:
enum Field {
SVEver = 0 * 4,
AES = 1 * 4,
RES0 = 2 * 4,
RES1 = 3 * 4,
BitPerm = 4 * 4,
BF16 = 5 * 4,
B16B16 = 6 * 4,
RES2 = 7 * 4,
SHA3 = 8 * 4,
RES3 = 9 * 4,
SM4 = 10 * 4,
I8MM = 11 * 4,
RES4 = 12 * 4,
F32MM = 13 * 4,
F64MM = 14 * 4,
RES5 = 15 * 4,
};
};
class MMFR1Reg final : public FeatureReg {
public:
FIELD_FETCHER(AFP, AFP, 0b0001);
private:
enum Field {
HAFDBS = 0 * 4,
VMIDBits = 1 * 4,
VH = 2 * 4,
HPDS = 3 * 4,
LO = 4 * 4,
PAN = 5 * 4,
SpecSEI = 6 * 4,
XNX = 7 * 4,
TWED = 8 * 4,
ETS = 9 * 4,
HCX = 10 * 4,
AFP = 11 * 4,
nTLBPA = 12 * 4,
TIDCP1 = 13 * 4,
CMOW = 14 * 4,
ECBHB = 15 * 4,
};
};
class ISAR2Reg final : public FeatureReg {
public:
FIELD_FETCHER(WFxt, WFxt, 0b0010);
FIELD_FETCHER(RPRES, RPRES, 0b0001);
FIELD_FETCHER(PACQARMA3, GPA3, 0b0001);
FIELD_FETCHER(MOPS, MOPS, 0b0001);
FIELD_FETCHER(HBC, BC, 0b0001);
uint64_t PAC_Minor() const {
return GetField(PAC_frac);
}
FIELD_FETCHER(CLRBHB, CLRBHB, 0b0001);
FIELD_FETCHER(SYSREG128, SYSREG_128, 0b0001);
FIELD_FETCHER(SYSINSTR128, SYSINSTR_128, 0b0001);
FIELD_FETCHER(PRFMSLC, PRFMSLC, 0b0001);
FIELD_FETCHER(RPRFM, RPRFM, 0b0001);
FIELD_FETCHER(CSSC, CSSC, 0b0001);
private:
enum Field {
WFxt = 0 * 4,
RPRES = 1 * 4,
GPA3 = 2 * 4,
APA3 = 3 * 4,
MOPS = 4 * 4,
BC = 5 * 4,
PAC_frac = 6 * 4,
CLRBHB = 7 * 4,
SYSREG_128 = 8 * 4,
SYSINSTR_128 = 9 * 4,
PRFMSLC = 10 * 4,
RES0 = 11 * 4,
RPRFM = 12 * 4,
CSSC = 13 * 4,
RES1 = 14 * 4,
ATS1A = 15 * 4,
};
};
#undef FIELD_FETCHER
ISAR0Reg ISAR0;
PFR0Reg PFR0;
PFR1Reg PFR1;
MIDRReg MIDR;
ISAR1Reg ISAR1;
MMFR0Reg MMFR0;
ZFR0Reg ZFR0;
MMFR2Reg MMFR2;
MMFR1Reg MMFR1;
ISAR2Reg ISAR2;
uint64_t FeatureBits[(FEXCore::ToUnderlying(Feature::MAX) / (sizeof(uint64_t) * 8)) + 1] {};
void SetFeature(Feature feat) {
const size_t DWordSelect = FEXCore::ToUnderlying(feat) / (sizeof(uint64_t) * 8);
const size_t BitSelect = FEXCore::ToUnderlying(feat) - (DWordSelect * (sizeof(uint64_t) * 8));
FeatureBits[DWordSelect] |= 1ULL << BitSelect;
}
};
void FillMIDRInformationViaLinux(FEXCore::HostFeatures* Features);
FEXCore::HostFeatures FetchHostFeatures(FEX::CPUFeatures& Features, bool SupportsCacheMaintenanceOps, uint64_t CTR, uint64_t MIDR);
FEXCore::HostFeatures FetchHostFeatures();
} // namespace FEX