diff options
-rw-r--r-- | arch/arm64/include/asm/cpufeature.h | 12 | ||||
-rw-r--r-- | arch/arm64/kernel/cpu_errata.c | 55 | ||||
-rw-r--r-- | arch/arm64/kernel/cpufeature.c | 13 |
3 files changed, 66 insertions, 14 deletions
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index a16eb0731290..09b0f2a80c8f 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -323,6 +323,18 @@ struct arm64_cpu_capabilities { bool sign; unsigned long hwcap; }; + /* + * A list of "matches/cpu_enable" pair for the same + * "capability" of the same "type" as described by the parent. + * Only matches(), cpu_enable() and fields relevant to these + * methods are significant in the list. The cpu_enable is + * invoked only if the corresponding entry "matches()". + * However, if a cpu_enable() method is associated + * with multiple matches(), care should be taken that either + * the match criteria are mutually exclusive, or that the + * method is robust against being called multiple times. + */ + const struct arm64_cpu_capabilities *match_list; }; }; diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index 9490b560d3fe..6de823a1be10 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -280,6 +280,38 @@ qcom_enable_link_stack_sanitization(const struct arm64_cpu_capabilities *entry) .type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM, \ CAP_MIDR_RANGE_LIST(midr_list) +/* + * Generic helper for handling capabilties with multiple (match,enable) pairs + * of call backs, sharing the same capability bit. + * Iterate over each entry to see if at least one matches. + */ +static bool multi_entry_cap_matches(const struct arm64_cpu_capabilities *entry, + int scope) +{ + const struct arm64_cpu_capabilities *caps; + + for (caps = entry->match_list; caps->matches; caps++) + if (caps->matches(caps, scope)) + return true; + + return false; +} + +/* + * Take appropriate action for all matching entries in the shared capability + * entry. + */ +static void +multi_entry_cap_cpu_enable(const struct arm64_cpu_capabilities *entry) +{ + const struct arm64_cpu_capabilities *caps; + + for (caps = entry->match_list; caps->matches; caps++) + if (caps->matches(caps, SCOPE_LOCAL_CPU) && + caps->cpu_enable) + caps->cpu_enable(caps); +} + #ifdef CONFIG_HARDEN_BRANCH_PREDICTOR /* @@ -302,6 +334,18 @@ static const struct midr_range qcom_bp_harden_cpus[] = { {}, }; +static const struct arm64_cpu_capabilities arm64_bp_harden_list[] = { + { + CAP_MIDR_RANGE_LIST(arm64_bp_harden_smccc_cpus), + .cpu_enable = enable_smccc_arch_workaround_1, + }, + { + CAP_MIDR_RANGE_LIST(qcom_bp_harden_cpus), + .cpu_enable = qcom_enable_link_stack_sanitization, + }, + {}, +}; + #endif const struct arm64_cpu_capabilities arm64_errata[] = { @@ -447,13 +491,10 @@ const struct arm64_cpu_capabilities arm64_errata[] = { #ifdef CONFIG_HARDEN_BRANCH_PREDICTOR { .capability = ARM64_HARDEN_BRANCH_PREDICTOR, - ERRATA_MIDR_RANGE_LIST(arm64_bp_harden_smccc_cpus), - .cpu_enable = enable_smccc_arch_workaround_1, - }, - { - .capability = ARM64_HARDEN_BRANCH_PREDICTOR, - ERRATA_MIDR_RANGE_LIST(qcom_bp_harden_cpus), - .cpu_enable = qcom_enable_link_stack_sanitization, + .type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM, + .matches = multi_entry_cap_matches, + .cpu_enable = multi_entry_cap_cpu_enable, + .match_list = arm64_bp_harden_list, }, { .capability = ARM64_HARDEN_BP_POST_GUEST_EXIT, diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 86e2b987a08e..00ed75398f60 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -1259,9 +1259,9 @@ static bool __this_cpu_has_cap(const struct arm64_cpu_capabilities *cap_array, return false; for (caps = cap_array; caps->matches; caps++) - if (caps->capability == cap && - caps->matches(caps, SCOPE_LOCAL_CPU)) - return true; + if (caps->capability == cap) + return caps->matches(caps, SCOPE_LOCAL_CPU); + return false; } @@ -1351,19 +1351,18 @@ static void __init enable_cpu_capabilities(u16 scope_mask) * Returns "false" on conflicts. */ static bool -__verify_local_cpu_caps(const struct arm64_cpu_capabilities *caps_list, +__verify_local_cpu_caps(const struct arm64_cpu_capabilities *caps, u16 scope_mask) { bool cpu_has_cap, system_has_cap; - const struct arm64_cpu_capabilities *caps; scope_mask &= ARM64_CPUCAP_SCOPE_MASK; - for (caps = caps_list; caps->matches; caps++) { + for (; caps->matches; caps++) { if (!(caps->type & scope_mask)) continue; - cpu_has_cap = __this_cpu_has_cap(caps_list, caps->capability); + cpu_has_cap = caps->matches(caps, SCOPE_LOCAL_CPU); system_has_cap = cpus_have_cap(caps->capability); if (system_has_cap) { |