|
@@ -23,12 +23,14 @@
|
|
|
#include <linux/sort.h>
|
|
|
#include <linux/stop_machine.h>
|
|
|
#include <linux/types.h>
|
|
|
+#include <linux/mm.h>
|
|
|
#include <asm/cpu.h>
|
|
|
#include <asm/cpufeature.h>
|
|
|
#include <asm/cpu_ops.h>
|
|
|
#include <asm/mmu_context.h>
|
|
|
#include <asm/processor.h>
|
|
|
#include <asm/sysreg.h>
|
|
|
+#include <asm/traps.h>
|
|
|
#include <asm/virt.h>
|
|
|
|
|
|
unsigned long elf_hwcap __read_mostly;
|
|
@@ -52,9 +54,10 @@ EXPORT_SYMBOL(cpu_hwcaps);
|
|
|
DEFINE_STATIC_KEY_ARRAY_FALSE(cpu_hwcap_keys, ARM64_NCAPS);
|
|
|
EXPORT_SYMBOL(cpu_hwcap_keys);
|
|
|
|
|
|
-#define __ARM64_FTR_BITS(SIGNED, STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL) \
|
|
|
+#define __ARM64_FTR_BITS(SIGNED, VISIBLE, STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL) \
|
|
|
{ \
|
|
|
.sign = SIGNED, \
|
|
|
+ .visible = VISIBLE, \
|
|
|
.strict = STRICT, \
|
|
|
.type = TYPE, \
|
|
|
.shift = SHIFT, \
|
|
@@ -63,12 +66,12 @@ EXPORT_SYMBOL(cpu_hwcap_keys);
|
|
|
}
|
|
|
|
|
|
/* Define a feature with unsigned values */
|
|
|
-#define ARM64_FTR_BITS(STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL) \
|
|
|
- __ARM64_FTR_BITS(FTR_UNSIGNED, STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL)
|
|
|
+#define ARM64_FTR_BITS(VISIBLE, STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL) \
|
|
|
+ __ARM64_FTR_BITS(FTR_UNSIGNED, VISIBLE, STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL)
|
|
|
|
|
|
/* Define a feature with a signed value */
|
|
|
-#define S_ARM64_FTR_BITS(STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL) \
|
|
|
- __ARM64_FTR_BITS(FTR_SIGNED, STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL)
|
|
|
+#define S_ARM64_FTR_BITS(VISIBLE, STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL) \
|
|
|
+ __ARM64_FTR_BITS(FTR_SIGNED, VISIBLE, STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL)
|
|
|
|
|
|
#define ARM64_FTR_END \
|
|
|
{ \
|
|
@@ -80,85 +83,80 @@ static bool __maybe_unused
|
|
|
cpufeature_pan_not_uao(const struct arm64_cpu_capabilities *entry, int __unused);
|
|
|
|
|
|
|
|
|
+/*
|
|
|
+ * NOTE: Any changes to the visibility of features should be kept in
|
|
|
+ * sync with the documentation of the CPU feature register ABI.
|
|
|
+ */
|
|
|
static const struct arm64_ftr_bits ftr_id_aa64isar0[] = {
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 32, 32, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64ISAR0_RDM_SHIFT, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 24, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR0_ATOMICS_SHIFT, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR0_CRC32_SHIFT, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR0_SHA2_SHIFT, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR0_SHA1_SHIFT, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR0_AES_SHIFT, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 0, 4, 0), /* RAZ */
|
|
|
+ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_EXACT, ID_AA64ISAR0_RDM_SHIFT, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR0_ATOMICS_SHIFT, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR0_CRC32_SHIFT, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR0_SHA2_SHIFT, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR0_SHA1_SHIFT, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR0_AES_SHIFT, 4, 0),
|
|
|
ARM64_FTR_END,
|
|
|
};
|
|
|
|
|
|
static const struct arm64_ftr_bits ftr_id_aa64pfr0[] = {
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 32, 32, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 28, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64PFR0_GIC_SHIFT, 4, 0),
|
|
|
- S_ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_ASIMD_SHIFT, 4, ID_AA64PFR0_ASIMD_NI),
|
|
|
- S_ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_FP_SHIFT, 4, ID_AA64PFR0_FP_NI),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64PFR0_GIC_SHIFT, 4, 0),
|
|
|
+ S_ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_ASIMD_SHIFT, 4, ID_AA64PFR0_ASIMD_NI),
|
|
|
+ S_ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_FP_SHIFT, 4, ID_AA64PFR0_FP_NI),
|
|
|
/* Linux doesn't care about the EL3 */
|
|
|
- ARM64_FTR_BITS(FTR_NONSTRICT, FTR_EXACT, ID_AA64PFR0_EL3_SHIFT, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64PFR0_EL2_SHIFT, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64PFR0_EL1_SHIFT, 4, ID_AA64PFR0_EL1_64BIT_ONLY),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64PFR0_EL0_SHIFT, 4, ID_AA64PFR0_EL0_64BIT_ONLY),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_AA64PFR0_EL3_SHIFT, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64PFR0_EL2_SHIFT, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64PFR0_EL1_SHIFT, 4, ID_AA64PFR0_EL1_64BIT_ONLY),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64PFR0_EL0_SHIFT, 4, ID_AA64PFR0_EL0_64BIT_ONLY),
|
|
|
ARM64_FTR_END,
|
|
|
};
|
|
|
|
|
|
static const struct arm64_ftr_bits ftr_id_aa64mmfr0[] = {
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 32, 32, 0),
|
|
|
- S_ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR0_TGRAN4_SHIFT, 4, ID_AA64MMFR0_TGRAN4_NI),
|
|
|
- S_ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR0_TGRAN64_SHIFT, 4, ID_AA64MMFR0_TGRAN64_NI),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR0_TGRAN16_SHIFT, 4, ID_AA64MMFR0_TGRAN16_NI),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR0_BIGENDEL0_SHIFT, 4, 0),
|
|
|
+ S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64MMFR0_TGRAN4_SHIFT, 4, ID_AA64MMFR0_TGRAN4_NI),
|
|
|
+ S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64MMFR0_TGRAN64_SHIFT, 4, ID_AA64MMFR0_TGRAN64_NI),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64MMFR0_TGRAN16_SHIFT, 4, ID_AA64MMFR0_TGRAN16_NI),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64MMFR0_BIGENDEL0_SHIFT, 4, 0),
|
|
|
/* Linux shouldn't care about secure memory */
|
|
|
- ARM64_FTR_BITS(FTR_NONSTRICT, FTR_EXACT, ID_AA64MMFR0_SNSMEM_SHIFT, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR0_BIGENDEL_SHIFT, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR0_ASID_SHIFT, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_AA64MMFR0_SNSMEM_SHIFT, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64MMFR0_BIGENDEL_SHIFT, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64MMFR0_ASID_SHIFT, 4, 0),
|
|
|
/*
|
|
|
* Differing PARange is fine as long as all peripherals and memory are mapped
|
|
|
* within the minimum PARange of all CPUs
|
|
|
*/
|
|
|
- ARM64_FTR_BITS(FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64MMFR0_PARANGE_SHIFT, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64MMFR0_PARANGE_SHIFT, 4, 0),
|
|
|
ARM64_FTR_END,
|
|
|
};
|
|
|
|
|
|
static const struct arm64_ftr_bits ftr_id_aa64mmfr1[] = {
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 32, 32, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64MMFR1_PAN_SHIFT, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR1_LOR_SHIFT, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR1_HPD_SHIFT, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR1_VHE_SHIFT, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR1_VMIDBITS_SHIFT, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR1_HADBS_SHIFT, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64MMFR1_PAN_SHIFT, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64MMFR1_LOR_SHIFT, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64MMFR1_HPD_SHIFT, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64MMFR1_VHE_SHIFT, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64MMFR1_VMIDBITS_SHIFT, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64MMFR1_HADBS_SHIFT, 4, 0),
|
|
|
ARM64_FTR_END,
|
|
|
};
|
|
|
|
|
|
static const struct arm64_ftr_bits ftr_id_aa64mmfr2[] = {
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR2_LVA_SHIFT, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR2_IESB_SHIFT, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR2_LSM_SHIFT, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR2_UAO_SHIFT, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR2_CNP_SHIFT, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64MMFR2_LVA_SHIFT, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64MMFR2_IESB_SHIFT, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64MMFR2_LSM_SHIFT, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64MMFR2_UAO_SHIFT, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64MMFR2_CNP_SHIFT, 4, 0),
|
|
|
ARM64_FTR_END,
|
|
|
};
|
|
|
|
|
|
static const struct arm64_ftr_bits ftr_ctr[] = {
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 31, 1, 1), /* RAO */
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 28, 3, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_HIGHER_SAFE, 24, 4, 0), /* CWG */
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 20, 4, 0), /* ERG */
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 16, 4, 1), /* DminLine */
|
|
|
+ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_EXACT, 31, 1, 1), /* RAO */
|
|
|
+ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_HIGHER_SAFE, 24, 4, 0), /* CWG */
|
|
|
+ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, 20, 4, 0), /* ERG */
|
|
|
+ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, 16, 4, 1), /* DminLine */
|
|
|
/*
|
|
|
* Linux can handle differing I-cache policies. Userspace JITs will
|
|
|
* make use of *minLine.
|
|
|
* If we have differing I-cache policies, report it as the weakest - AIVIVT.
|
|
|
*/
|
|
|
- ARM64_FTR_BITS(FTR_NONSTRICT, FTR_EXACT, 14, 2, ICACHE_POLICY_AIVIVT), /* L1Ip */
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 4, 10, 0), /* RAZ */
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 0, 4, 0), /* IminLine */
|
|
|
+ ARM64_FTR_BITS(FTR_VISIBLE, FTR_NONSTRICT, FTR_EXACT, 14, 2, ICACHE_POLICY_AIVIVT), /* L1Ip */
|
|
|
+ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, 0, 4, 0), /* IminLine */
|
|
|
ARM64_FTR_END,
|
|
|
};
|
|
|
|
|
@@ -168,79 +166,78 @@ struct arm64_ftr_reg arm64_ftr_reg_ctrel0 = {
|
|
|
};
|
|
|
|
|
|
static const struct arm64_ftr_bits ftr_id_mmfr0[] = {
|
|
|
- S_ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 28, 4, 0xf), /* InnerShr */
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 24, 4, 0), /* FCSE */
|
|
|
- ARM64_FTR_BITS(FTR_NONSTRICT, FTR_LOWER_SAFE, 20, 4, 0), /* AuxReg */
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 16, 4, 0), /* TCM */
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 12, 4, 0), /* ShareLvl */
|
|
|
- S_ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 8, 4, 0xf), /* OuterShr */
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 4, 4, 0), /* PMSA */
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 0, 4, 0), /* VMSA */
|
|
|
+ S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, 28, 4, 0xf), /* InnerShr */
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, 24, 4, 0), /* FCSE */
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, 20, 4, 0), /* AuxReg */
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, 16, 4, 0), /* TCM */
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, 12, 4, 0), /* ShareLvl */
|
|
|
+ S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, 8, 4, 0xf), /* OuterShr */
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, 4, 4, 0), /* PMSA */
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, 0, 4, 0), /* VMSA */
|
|
|
ARM64_FTR_END,
|
|
|
};
|
|
|
|
|
|
static const struct arm64_ftr_bits ftr_id_aa64dfr0[] = {
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 32, 32, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_CTX_CMPS_SHIFT, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_WRPS_SHIFT, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_BRPS_SHIFT, 4, 0),
|
|
|
- S_ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64DFR0_PMUVER_SHIFT, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64DFR0_TRACEVER_SHIFT, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64DFR0_DEBUGVER_SHIFT, 4, 0x6),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, 36, 28, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64DFR0_PMSVER_SHIFT, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_CTX_CMPS_SHIFT, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_WRPS_SHIFT, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_BRPS_SHIFT, 4, 0),
|
|
|
+ /*
|
|
|
+ * We can instantiate multiple PMU instances with different levels
|
|
|
+ * of support.
|
|
|
+ */
|
|
|
+ S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_AA64DFR0_PMUVER_SHIFT, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64DFR0_TRACEVER_SHIFT, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64DFR0_DEBUGVER_SHIFT, 4, 0x6),
|
|
|
ARM64_FTR_END,
|
|
|
};
|
|
|
|
|
|
static const struct arm64_ftr_bits ftr_mvfr2[] = {
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 8, 24, 0), /* RAZ */
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 4, 4, 0), /* FPMisc */
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 0, 4, 0), /* SIMDMisc */
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, 4, 4, 0), /* FPMisc */
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, 0, 4, 0), /* SIMDMisc */
|
|
|
ARM64_FTR_END,
|
|
|
};
|
|
|
|
|
|
static const struct arm64_ftr_bits ftr_dczid[] = {
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 5, 27, 0), /* RAZ */
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 4, 1, 1), /* DZP */
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 0, 4, 0), /* BS */
|
|
|
+ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_EXACT, 4, 1, 1), /* DZP */
|
|
|
+ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, 0, 4, 0), /* BS */
|
|
|
ARM64_FTR_END,
|
|
|
};
|
|
|
|
|
|
|
|
|
static const struct arm64_ftr_bits ftr_id_isar5[] = {
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_ISAR5_RDM_SHIFT, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 20, 4, 0), /* RAZ */
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_ISAR5_CRC32_SHIFT, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_ISAR5_SHA2_SHIFT, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_ISAR5_SHA1_SHIFT, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_ISAR5_AES_SHIFT, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_ISAR5_SEVL_SHIFT, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_ISAR5_RDM_SHIFT, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_ISAR5_CRC32_SHIFT, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_ISAR5_SHA2_SHIFT, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_ISAR5_SHA1_SHIFT, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_ISAR5_AES_SHIFT, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_ISAR5_SEVL_SHIFT, 4, 0),
|
|
|
ARM64_FTR_END,
|
|
|
};
|
|
|
|
|
|
static const struct arm64_ftr_bits ftr_id_mmfr4[] = {
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 8, 24, 0), /* RAZ */
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 4, 4, 0), /* ac2 */
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 0, 4, 0), /* RAZ */
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, 4, 4, 0), /* ac2 */
|
|
|
ARM64_FTR_END,
|
|
|
};
|
|
|
|
|
|
static const struct arm64_ftr_bits ftr_id_pfr0[] = {
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 16, 16, 0), /* RAZ */
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 12, 4, 0), /* State3 */
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 8, 4, 0), /* State2 */
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 4, 4, 0), /* State1 */
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 0, 4, 0), /* State0 */
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, 12, 4, 0), /* State3 */
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, 8, 4, 0), /* State2 */
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, 4, 4, 0), /* State1 */
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, 0, 4, 0), /* State0 */
|
|
|
ARM64_FTR_END,
|
|
|
};
|
|
|
|
|
|
static const struct arm64_ftr_bits ftr_id_dfr0[] = {
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 28, 4, 0),
|
|
|
- S_ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 24, 4, 0xf), /* PerfMon */
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 20, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 16, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 12, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 8, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 4, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 0, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, 28, 4, 0),
|
|
|
+ S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, 24, 4, 0xf), /* PerfMon */
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, 20, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, 16, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, 12, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, 8, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, 4, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, 0, 4, 0),
|
|
|
ARM64_FTR_END,
|
|
|
};
|
|
|
|
|
@@ -251,29 +248,24 @@ static const struct arm64_ftr_bits ftr_id_dfr0[] = {
|
|
|
* id_isar[0-4], id_mmfr[1-3], id_pfr1, mvfr[0-1]
|
|
|
*/
|
|
|
static const struct arm64_ftr_bits ftr_generic_32bits[] = {
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 28, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 24, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 20, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 16, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 12, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 8, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 4, 4, 0),
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 0, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, 28, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, 24, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, 20, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, 16, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, 12, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, 8, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, 4, 4, 0),
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, 0, 4, 0),
|
|
|
ARM64_FTR_END,
|
|
|
};
|
|
|
|
|
|
-static const struct arm64_ftr_bits ftr_generic[] = {
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 0, 64, 0),
|
|
|
+/* Table for a single 32bit feature value */
|
|
|
+static const struct arm64_ftr_bits ftr_single32[] = {
|
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, 0, 32, 0),
|
|
|
ARM64_FTR_END,
|
|
|
};
|
|
|
|
|
|
-static const struct arm64_ftr_bits ftr_generic32[] = {
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 0, 32, 0),
|
|
|
- ARM64_FTR_END,
|
|
|
-};
|
|
|
-
|
|
|
-static const struct arm64_ftr_bits ftr_aa64raz[] = {
|
|
|
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 0, 64, 0),
|
|
|
+static const struct arm64_ftr_bits ftr_raz[] = {
|
|
|
ARM64_FTR_END,
|
|
|
};
|
|
|
|
|
@@ -314,15 +306,15 @@ static const struct __ftr_reg_entry {
|
|
|
|
|
|
/* Op1 = 0, CRn = 0, CRm = 4 */
|
|
|
ARM64_FTR_REG(SYS_ID_AA64PFR0_EL1, ftr_id_aa64pfr0),
|
|
|
- ARM64_FTR_REG(SYS_ID_AA64PFR1_EL1, ftr_aa64raz),
|
|
|
+ ARM64_FTR_REG(SYS_ID_AA64PFR1_EL1, ftr_raz),
|
|
|
|
|
|
/* Op1 = 0, CRn = 0, CRm = 5 */
|
|
|
ARM64_FTR_REG(SYS_ID_AA64DFR0_EL1, ftr_id_aa64dfr0),
|
|
|
- ARM64_FTR_REG(SYS_ID_AA64DFR1_EL1, ftr_generic),
|
|
|
+ ARM64_FTR_REG(SYS_ID_AA64DFR1_EL1, ftr_raz),
|
|
|
|
|
|
/* Op1 = 0, CRn = 0, CRm = 6 */
|
|
|
ARM64_FTR_REG(SYS_ID_AA64ISAR0_EL1, ftr_id_aa64isar0),
|
|
|
- ARM64_FTR_REG(SYS_ID_AA64ISAR1_EL1, ftr_aa64raz),
|
|
|
+ ARM64_FTR_REG(SYS_ID_AA64ISAR1_EL1, ftr_raz),
|
|
|
|
|
|
/* Op1 = 0, CRn = 0, CRm = 7 */
|
|
|
ARM64_FTR_REG(SYS_ID_AA64MMFR0_EL1, ftr_id_aa64mmfr0),
|
|
@@ -334,7 +326,7 @@ static const struct __ftr_reg_entry {
|
|
|
ARM64_FTR_REG(SYS_DCZID_EL0, ftr_dczid),
|
|
|
|
|
|
/* Op1 = 3, CRn = 14, CRm = 0 */
|
|
|
- ARM64_FTR_REG(SYS_CNTFRQ_EL0, ftr_generic32),
|
|
|
+ ARM64_FTR_REG(SYS_CNTFRQ_EL0, ftr_single32),
|
|
|
};
|
|
|
|
|
|
static int search_cmp_ftr_reg(const void *id, const void *regp)
|
|
@@ -410,25 +402,43 @@ static void __init sort_ftr_regs(void)
|
|
|
/*
|
|
|
* Initialise the CPU feature register from Boot CPU values.
|
|
|
* Also initiliases the strict_mask for the register.
|
|
|
+ * Any bits that are not covered by an arm64_ftr_bits entry are considered
|
|
|
+ * RES0 for the system-wide value, and must strictly match.
|
|
|
*/
|
|
|
static void __init init_cpu_ftr_reg(u32 sys_reg, u64 new)
|
|
|
{
|
|
|
u64 val = 0;
|
|
|
u64 strict_mask = ~0x0ULL;
|
|
|
+ u64 user_mask = 0;
|
|
|
+ u64 valid_mask = 0;
|
|
|
+
|
|
|
const struct arm64_ftr_bits *ftrp;
|
|
|
struct arm64_ftr_reg *reg = get_arm64_ftr_reg(sys_reg);
|
|
|
|
|
|
BUG_ON(!reg);
|
|
|
|
|
|
for (ftrp = reg->ftr_bits; ftrp->width; ftrp++) {
|
|
|
+ u64 ftr_mask = arm64_ftr_mask(ftrp);
|
|
|
s64 ftr_new = arm64_ftr_value(ftrp, new);
|
|
|
|
|
|
val = arm64_ftr_set_value(ftrp, val, ftr_new);
|
|
|
+
|
|
|
+ valid_mask |= ftr_mask;
|
|
|
if (!ftrp->strict)
|
|
|
- strict_mask &= ~arm64_ftr_mask(ftrp);
|
|
|
+ strict_mask &= ~ftr_mask;
|
|
|
+ if (ftrp->visible)
|
|
|
+ user_mask |= ftr_mask;
|
|
|
+ else
|
|
|
+ reg->user_val = arm64_ftr_set_value(ftrp,
|
|
|
+ reg->user_val,
|
|
|
+ ftrp->safe_val);
|
|
|
}
|
|
|
+
|
|
|
+ val &= valid_mask;
|
|
|
+
|
|
|
reg->sys_val = val;
|
|
|
reg->strict_mask = strict_mask;
|
|
|
+ reg->user_mask = user_mask;
|
|
|
}
|
|
|
|
|
|
void __init init_cpu_features(struct cpuinfo_arm64 *info)
|
|
@@ -635,6 +645,9 @@ u64 read_system_reg(u32 id)
|
|
|
return regp->sys_val;
|
|
|
}
|
|
|
|
|
|
+#define read_sysreg_case(r) \
|
|
|
+ case r: return read_sysreg_s(r)
|
|
|
+
|
|
|
/*
|
|
|
* __raw_read_system_reg() - Used by a STARTING cpu before cpuinfo is populated.
|
|
|
* Read the system register on the current CPU
|
|
@@ -642,36 +655,37 @@ u64 read_system_reg(u32 id)
|
|
|
static u64 __raw_read_system_reg(u32 sys_id)
|
|
|
{
|
|
|
switch (sys_id) {
|
|
|
- case SYS_ID_PFR0_EL1: return read_cpuid(ID_PFR0_EL1);
|
|
|
- case SYS_ID_PFR1_EL1: return read_cpuid(ID_PFR1_EL1);
|
|
|
- case SYS_ID_DFR0_EL1: return read_cpuid(ID_DFR0_EL1);
|
|
|
- case SYS_ID_MMFR0_EL1: return read_cpuid(ID_MMFR0_EL1);
|
|
|
- case SYS_ID_MMFR1_EL1: return read_cpuid(ID_MMFR1_EL1);
|
|
|
- case SYS_ID_MMFR2_EL1: return read_cpuid(ID_MMFR2_EL1);
|
|
|
- case SYS_ID_MMFR3_EL1: return read_cpuid(ID_MMFR3_EL1);
|
|
|
- case SYS_ID_ISAR0_EL1: return read_cpuid(ID_ISAR0_EL1);
|
|
|
- case SYS_ID_ISAR1_EL1: return read_cpuid(ID_ISAR1_EL1);
|
|
|
- case SYS_ID_ISAR2_EL1: return read_cpuid(ID_ISAR2_EL1);
|
|
|
- case SYS_ID_ISAR3_EL1: return read_cpuid(ID_ISAR3_EL1);
|
|
|
- case SYS_ID_ISAR4_EL1: return read_cpuid(ID_ISAR4_EL1);
|
|
|
- case SYS_ID_ISAR5_EL1: return read_cpuid(ID_ISAR4_EL1);
|
|
|
- case SYS_MVFR0_EL1: return read_cpuid(MVFR0_EL1);
|
|
|
- case SYS_MVFR1_EL1: return read_cpuid(MVFR1_EL1);
|
|
|
- case SYS_MVFR2_EL1: return read_cpuid(MVFR2_EL1);
|
|
|
-
|
|
|
- case SYS_ID_AA64PFR0_EL1: return read_cpuid(ID_AA64PFR0_EL1);
|
|
|
- case SYS_ID_AA64PFR1_EL1: return read_cpuid(ID_AA64PFR0_EL1);
|
|
|
- case SYS_ID_AA64DFR0_EL1: return read_cpuid(ID_AA64DFR0_EL1);
|
|
|
- case SYS_ID_AA64DFR1_EL1: return read_cpuid(ID_AA64DFR0_EL1);
|
|
|
- case SYS_ID_AA64MMFR0_EL1: return read_cpuid(ID_AA64MMFR0_EL1);
|
|
|
- case SYS_ID_AA64MMFR1_EL1: return read_cpuid(ID_AA64MMFR1_EL1);
|
|
|
- case SYS_ID_AA64MMFR2_EL1: return read_cpuid(ID_AA64MMFR2_EL1);
|
|
|
- case SYS_ID_AA64ISAR0_EL1: return read_cpuid(ID_AA64ISAR0_EL1);
|
|
|
- case SYS_ID_AA64ISAR1_EL1: return read_cpuid(ID_AA64ISAR1_EL1);
|
|
|
-
|
|
|
- case SYS_CNTFRQ_EL0: return read_cpuid(CNTFRQ_EL0);
|
|
|
- case SYS_CTR_EL0: return read_cpuid(CTR_EL0);
|
|
|
- case SYS_DCZID_EL0: return read_cpuid(DCZID_EL0);
|
|
|
+ read_sysreg_case(SYS_ID_PFR0_EL1);
|
|
|
+ read_sysreg_case(SYS_ID_PFR1_EL1);
|
|
|
+ read_sysreg_case(SYS_ID_DFR0_EL1);
|
|
|
+ read_sysreg_case(SYS_ID_MMFR0_EL1);
|
|
|
+ read_sysreg_case(SYS_ID_MMFR1_EL1);
|
|
|
+ read_sysreg_case(SYS_ID_MMFR2_EL1);
|
|
|
+ read_sysreg_case(SYS_ID_MMFR3_EL1);
|
|
|
+ read_sysreg_case(SYS_ID_ISAR0_EL1);
|
|
|
+ read_sysreg_case(SYS_ID_ISAR1_EL1);
|
|
|
+ read_sysreg_case(SYS_ID_ISAR2_EL1);
|
|
|
+ read_sysreg_case(SYS_ID_ISAR3_EL1);
|
|
|
+ read_sysreg_case(SYS_ID_ISAR4_EL1);
|
|
|
+ read_sysreg_case(SYS_ID_ISAR5_EL1);
|
|
|
+ read_sysreg_case(SYS_MVFR0_EL1);
|
|
|
+ read_sysreg_case(SYS_MVFR1_EL1);
|
|
|
+ read_sysreg_case(SYS_MVFR2_EL1);
|
|
|
+
|
|
|
+ read_sysreg_case(SYS_ID_AA64PFR0_EL1);
|
|
|
+ read_sysreg_case(SYS_ID_AA64PFR1_EL1);
|
|
|
+ read_sysreg_case(SYS_ID_AA64DFR0_EL1);
|
|
|
+ read_sysreg_case(SYS_ID_AA64DFR1_EL1);
|
|
|
+ read_sysreg_case(SYS_ID_AA64MMFR0_EL1);
|
|
|
+ read_sysreg_case(SYS_ID_AA64MMFR1_EL1);
|
|
|
+ read_sysreg_case(SYS_ID_AA64MMFR2_EL1);
|
|
|
+ read_sysreg_case(SYS_ID_AA64ISAR0_EL1);
|
|
|
+ read_sysreg_case(SYS_ID_AA64ISAR1_EL1);
|
|
|
+
|
|
|
+ read_sysreg_case(SYS_CNTFRQ_EL0);
|
|
|
+ read_sysreg_case(SYS_CTR_EL0);
|
|
|
+ read_sysreg_case(SYS_DCZID_EL0);
|
|
|
+
|
|
|
default:
|
|
|
BUG();
|
|
|
return 0;
|
|
@@ -720,13 +734,11 @@ static bool has_useable_gicv3_cpuif(const struct arm64_cpu_capabilities *entry,
|
|
|
static bool has_no_hw_prefetch(const struct arm64_cpu_capabilities *entry, int __unused)
|
|
|
{
|
|
|
u32 midr = read_cpuid_id();
|
|
|
- u32 rv_min, rv_max;
|
|
|
|
|
|
/* Cavium ThunderX pass 1.x and 2.x */
|
|
|
- rv_min = 0;
|
|
|
- rv_max = (1 << MIDR_VARIANT_SHIFT) | MIDR_REVISION_MASK;
|
|
|
-
|
|
|
- return MIDR_IS_CPU_MODEL_RANGE(midr, MIDR_THUNDERX, rv_min, rv_max);
|
|
|
+ return MIDR_IS_CPU_MODEL_RANGE(midr, MIDR_THUNDERX,
|
|
|
+ MIDR_CPU_VAR_REV(0, 0),
|
|
|
+ MIDR_CPU_VAR_REV(1, MIDR_REVISION_MASK));
|
|
|
}
|
|
|
|
|
|
static bool runs_at_el2(const struct arm64_cpu_capabilities *entry, int __unused)
|
|
@@ -737,7 +749,7 @@ static bool runs_at_el2(const struct arm64_cpu_capabilities *entry, int __unused
|
|
|
static bool hyp_offset_low(const struct arm64_cpu_capabilities *entry,
|
|
|
int __unused)
|
|
|
{
|
|
|
- phys_addr_t idmap_addr = virt_to_phys(__hyp_idmap_text_start);
|
|
|
+ phys_addr_t idmap_addr = __pa_symbol(__hyp_idmap_text_start);
|
|
|
|
|
|
/*
|
|
|
* Activate the lower HYP offset only if:
|
|
@@ -806,7 +818,10 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
|
|
|
.sys_reg = SYS_ID_AA64MMFR2_EL1,
|
|
|
.field_pos = ID_AA64MMFR2_UAO_SHIFT,
|
|
|
.min_field_value = 1,
|
|
|
- .enable = cpu_enable_uao,
|
|
|
+ /*
|
|
|
+ * We rely on stop_machine() calling uao_thread_switch() to set
|
|
|
+ * UAO immediately after patching.
|
|
|
+ */
|
|
|
},
|
|
|
#endif /* CONFIG_ARM64_UAO */
|
|
|
#ifdef CONFIG_ARM64_PAN
|
|
@@ -868,6 +883,7 @@ static const struct arm64_cpu_capabilities arm64_elf_hwcaps[] = {
|
|
|
HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SHA2_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_SHA2),
|
|
|
HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_CRC32_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_CRC32),
|
|
|
HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_ATOMICS_SHIFT, FTR_UNSIGNED, 2, CAP_HWCAP, HWCAP_ATOMICS),
|
|
|
+ HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_RDM_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_ASIMDRDM),
|
|
|
HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_FP_SHIFT, FTR_SIGNED, 0, CAP_HWCAP, HWCAP_FP),
|
|
|
HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_FP_SHIFT, FTR_SIGNED, 1, CAP_HWCAP, HWCAP_FPHP),
|
|
|
HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_ASIMD_SHIFT, FTR_SIGNED, 0, CAP_HWCAP, HWCAP_ASIMD),
|
|
@@ -933,6 +949,8 @@ static bool cpus_have_elf_hwcap(const struct arm64_cpu_capabilities *cap)
|
|
|
|
|
|
static void __init setup_elf_hwcaps(const struct arm64_cpu_capabilities *hwcaps)
|
|
|
{
|
|
|
+ /* We support emulation of accesses to CPU ID feature registers */
|
|
|
+ elf_hwcap |= HWCAP_CPUID;
|
|
|
for (; hwcaps->matches; hwcaps++)
|
|
|
if (hwcaps->matches(hwcaps, hwcaps->def_scope))
|
|
|
cap_set_elf_hwcap(hwcaps);
|
|
@@ -1120,3 +1138,101 @@ cpufeature_pan_not_uao(const struct arm64_cpu_capabilities *entry, int __unused)
|
|
|
{
|
|
|
return (cpus_have_const_cap(ARM64_HAS_PAN) && !cpus_have_const_cap(ARM64_HAS_UAO));
|
|
|
}
|
|
|
+
|
|
|
+/*
|
|
|
+ * We emulate only the following system register space.
|
|
|
+ * Op0 = 0x3, CRn = 0x0, Op1 = 0x0, CRm = [0, 4 - 7]
|
|
|
+ * See Table C5-6 System instruction encodings for System register accesses,
|
|
|
+ * ARMv8 ARM(ARM DDI 0487A.f) for more details.
|
|
|
+ */
|
|
|
+static inline bool __attribute_const__ is_emulated(u32 id)
|
|
|
+{
|
|
|
+ return (sys_reg_Op0(id) == 0x3 &&
|
|
|
+ sys_reg_CRn(id) == 0x0 &&
|
|
|
+ sys_reg_Op1(id) == 0x0 &&
|
|
|
+ (sys_reg_CRm(id) == 0 ||
|
|
|
+ ((sys_reg_CRm(id) >= 4) && (sys_reg_CRm(id) <= 7))));
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * With CRm == 0, reg should be one of :
|
|
|
+ * MIDR_EL1, MPIDR_EL1 or REVIDR_EL1.
|
|
|
+ */
|
|
|
+static inline int emulate_id_reg(u32 id, u64 *valp)
|
|
|
+{
|
|
|
+ switch (id) {
|
|
|
+ case SYS_MIDR_EL1:
|
|
|
+ *valp = read_cpuid_id();
|
|
|
+ break;
|
|
|
+ case SYS_MPIDR_EL1:
|
|
|
+ *valp = SYS_MPIDR_SAFE_VAL;
|
|
|
+ break;
|
|
|
+ case SYS_REVIDR_EL1:
|
|
|
+ /* IMPLEMENTATION DEFINED values are emulated with 0 */
|
|
|
+ *valp = 0;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int emulate_sys_reg(u32 id, u64 *valp)
|
|
|
+{
|
|
|
+ struct arm64_ftr_reg *regp;
|
|
|
+
|
|
|
+ if (!is_emulated(id))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (sys_reg_CRm(id) == 0)
|
|
|
+ return emulate_id_reg(id, valp);
|
|
|
+
|
|
|
+ regp = get_arm64_ftr_reg(id);
|
|
|
+ if (regp)
|
|
|
+ *valp = arm64_ftr_reg_user_value(regp);
|
|
|
+ else
|
|
|
+ /*
|
|
|
+ * The untracked registers are either IMPLEMENTATION DEFINED
|
|
|
+ * (e.g, ID_AFR0_EL1) or reserved RAZ.
|
|
|
+ */
|
|
|
+ *valp = 0;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int emulate_mrs(struct pt_regs *regs, u32 insn)
|
|
|
+{
|
|
|
+ int rc;
|
|
|
+ u32 sys_reg, dst;
|
|
|
+ u64 val;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * sys_reg values are defined as used in mrs/msr instruction.
|
|
|
+ * shift the imm value to get the encoding.
|
|
|
+ */
|
|
|
+ sys_reg = (u32)aarch64_insn_decode_immediate(AARCH64_INSN_IMM_16, insn) << 5;
|
|
|
+ rc = emulate_sys_reg(sys_reg, &val);
|
|
|
+ if (!rc) {
|
|
|
+ dst = aarch64_insn_decode_register(AARCH64_INSN_REGTYPE_RT, insn);
|
|
|
+ pt_regs_write_reg(regs, dst, val);
|
|
|
+ regs->pc += 4;
|
|
|
+ }
|
|
|
+
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
+static struct undef_hook mrs_hook = {
|
|
|
+ .instr_mask = 0xfff00000,
|
|
|
+ .instr_val = 0xd5300000,
|
|
|
+ .pstate_mask = COMPAT_PSR_MODE_MASK,
|
|
|
+ .pstate_val = PSR_MODE_EL0t,
|
|
|
+ .fn = emulate_mrs,
|
|
|
+};
|
|
|
+
|
|
|
+static int __init enable_mrs_emulation(void)
|
|
|
+{
|
|
|
+ register_undef_hook(&mrs_hook);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+late_initcall(enable_mrs_emulation);
|