| From foo@baz Sun 27 Oct 2019 09:50:54 AM CET |
| From: Ard Biesheuvel <ard.biesheuvel@linaro.org> |
| Date: Thu, 24 Oct 2019 14:48:00 +0200 |
| Subject: arm64: capabilities: Unify the verification |
| To: stable@vger.kernel.org |
| Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>, Will Deacon <will@kernel.org>, Catalin Marinas <catalin.marinas@arm.com>, Marc Zyngier <maz@kernel.org>, Mark Rutland <mark.rutland@arm.com>, Suzuki K Poulose <suzuki.poulose@arm.com>, Jeremy Linton <jeremy.linton@arm.com>, Andre Przywara <andre.przywara@arm.com>, Alexandru Elisei <alexandru.elisei@arm.com>, Dave Martin <dave.martin@arm.com>, Will Deacon <will.deacon@arm.com> |
| Message-ID: <20191024124833.4158-16-ard.biesheuvel@linaro.org> |
| |
| From: Suzuki K Poulose <suzuki.poulose@arm.com> |
| |
| [ Upstream commit eaac4d83daa50fc1b9b7850346e9a62adfd4647e ] |
| |
| Now that each capability describes how to treat the conflicts |
| of CPU cap state vs System wide cap state, we can unify the |
| verification logic to a single place. |
| |
| Reviewed-by: Dave Martin <dave.martin@arm.com> |
| Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com> |
| Signed-off-by: Will Deacon <will.deacon@arm.com> |
| Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| arch/arm64/kernel/cpufeature.c | 91 ++++++++++++++++++++++++++--------------- |
| 1 file changed, 58 insertions(+), 33 deletions(-) |
| |
| --- a/arch/arm64/kernel/cpufeature.c |
| +++ b/arch/arm64/kernel/cpufeature.c |
| @@ -1229,6 +1229,58 @@ static inline void set_sys_caps_initiali |
| } |
| |
| /* |
| + * Run through the list of capabilities to check for conflicts. |
| + * If the system has already detected a capability, take necessary |
| + * action on this CPU. |
| + * |
| + * Returns "false" on conflicts. |
| + */ |
| +static bool |
| +__verify_local_cpu_caps(const struct arm64_cpu_capabilities *caps_list) |
| +{ |
| + bool cpu_has_cap, system_has_cap; |
| + const struct arm64_cpu_capabilities *caps; |
| + |
| + for (caps = caps_list; caps->matches; caps++) { |
| + cpu_has_cap = __this_cpu_has_cap(caps_list, caps->capability); |
| + system_has_cap = cpus_have_cap(caps->capability); |
| + |
| + if (system_has_cap) { |
| + /* |
| + * Check if the new CPU misses an advertised feature, |
| + * which is not safe to miss. |
| + */ |
| + if (!cpu_has_cap && !cpucap_late_cpu_optional(caps)) |
| + break; |
| + /* |
| + * We have to issue cpu_enable() irrespective of |
| + * whether the CPU has it or not, as it is enabeld |
| + * system wide. It is upto the call back to take |
| + * appropriate action on this CPU. |
| + */ |
| + if (caps->cpu_enable) |
| + caps->cpu_enable(caps); |
| + } else { |
| + /* |
| + * Check if the CPU has this capability if it isn't |
| + * safe to have when the system doesn't. |
| + */ |
| + if (cpu_has_cap && !cpucap_late_cpu_permitted(caps)) |
| + break; |
| + } |
| + } |
| + |
| + if (caps->matches) { |
| + pr_crit("CPU%d: Detected conflict for capability %d (%s), System: %d, CPU: %d\n", |
| + smp_processor_id(), caps->capability, |
| + caps->desc, system_has_cap, cpu_has_cap); |
| + return false; |
| + } |
| + |
| + return true; |
| +} |
| + |
| +/* |
| * Check for CPU features that are used in early boot |
| * based on the Boot CPU value. |
| */ |
| @@ -1250,25 +1302,10 @@ verify_local_elf_hwcaps(const struct arm |
| } |
| } |
| |
| -static void |
| -verify_local_cpu_features(const struct arm64_cpu_capabilities *caps_list) |
| +static void verify_local_cpu_features(void) |
| { |
| - const struct arm64_cpu_capabilities *caps = caps_list; |
| - for (; caps->matches; caps++) { |
| - if (!cpus_have_cap(caps->capability)) |
| - continue; |
| - /* |
| - * If the new CPU misses an advertised feature, we cannot proceed |
| - * further, park the cpu. |
| - */ |
| - if (!__this_cpu_has_cap(caps_list, caps->capability)) { |
| - pr_crit("CPU%d: missing feature: %s\n", |
| - smp_processor_id(), caps->desc); |
| - cpu_die_early(); |
| - } |
| - if (caps->cpu_enable) |
| - caps->cpu_enable(caps); |
| - } |
| + if (!__verify_local_cpu_caps(arm64_features)) |
| + cpu_die_early(); |
| } |
| |
| /* |
| @@ -1278,20 +1315,8 @@ verify_local_cpu_features(const struct a |
| */ |
| static void verify_local_cpu_errata_workarounds(void) |
| { |
| - const struct arm64_cpu_capabilities *caps = arm64_errata; |
| - |
| - for (; caps->matches; caps++) { |
| - if (cpus_have_cap(caps->capability)) { |
| - if (caps->cpu_enable) |
| - caps->cpu_enable(caps); |
| - } else if (caps->matches(caps, SCOPE_LOCAL_CPU)) { |
| - pr_crit("CPU%d: Requires work around for %s, not detected" |
| - " at boot time\n", |
| - smp_processor_id(), |
| - caps->desc ? : "an erratum"); |
| - cpu_die_early(); |
| - } |
| - } |
| + if (!__verify_local_cpu_caps(arm64_errata)) |
| + cpu_die_early(); |
| } |
| |
| static void update_cpu_errata_workarounds(void) |
| @@ -1315,7 +1340,7 @@ static void __init enable_errata_workaro |
| static void verify_local_cpu_capabilities(void) |
| { |
| verify_local_cpu_errata_workarounds(); |
| - verify_local_cpu_features(arm64_features); |
| + verify_local_cpu_features(); |
| verify_local_elf_hwcaps(arm64_elf_hwcaps); |
| if (system_supports_32bit_el0()) |
| verify_local_elf_hwcaps(compat_elf_hwcaps); |