Commit deeaac51 authored by Kristina Martsenko's avatar Kristina Martsenko Committed by Catalin Marinas

arm64: cpufeature: handle conflicts based on capability

Each system capability can be of either boot, local, or system scope,
depending on when the state of the capability is finalized. When we
detect a conflict on a late CPU, we either offline the CPU or panic the
system. We currently always panic if the conflict is caused by a boot
scope capability, and offline the CPU if the conflict is caused by a
local or system scope capability.

We're going to want to add a new capability (for pointer authentication)
which needs to be boot scope but doesn't need to panic the system when a
conflict is detected. So add a new flag to specify whether the
capability requires the system to panic or not. Current boot scope
capabilities are updated to set the flag, so there should be no
functional change as a result of this patch.
Signed-off-by: default avatarAmit Daniel Kachhap <amit.kachhap@arm.com>
Signed-off-by: default avatarKristina Martsenko <kristina.martsenko@arm.com>
Reviewed-by: default avatarVincenzo Frascino <vincenzo.frascino@arm.com>
Reviewed-by: default avatarSuzuki K Poulose <suzuki.poulose@arm.com>
Reviewed-by: default avatarKees Cook <keescook@chromium.org>
Signed-off-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
parent 8c176e16
...@@ -208,6 +208,10 @@ extern struct arm64_ftr_reg arm64_ftr_reg_ctrel0; ...@@ -208,6 +208,10 @@ extern struct arm64_ftr_reg arm64_ftr_reg_ctrel0;
* In some non-typical cases either both (a) and (b), or neither, * In some non-typical cases either both (a) and (b), or neither,
* should be permitted. This can be described by including neither * should be permitted. This can be described by including neither
* or both flags in the capability's type field. * or both flags in the capability's type field.
*
* In case of a conflict, the CPU is prevented from booting. If the
* ARM64_CPUCAP_PANIC_ON_CONFLICT flag is specified for the capability,
* then a kernel panic is triggered.
*/ */
...@@ -240,6 +244,8 @@ extern struct arm64_ftr_reg arm64_ftr_reg_ctrel0; ...@@ -240,6 +244,8 @@ extern struct arm64_ftr_reg arm64_ftr_reg_ctrel0;
#define ARM64_CPUCAP_PERMITTED_FOR_LATE_CPU ((u16)BIT(4)) #define ARM64_CPUCAP_PERMITTED_FOR_LATE_CPU ((u16)BIT(4))
/* Is it safe for a late CPU to miss this capability when system has it */ /* Is it safe for a late CPU to miss this capability when system has it */
#define ARM64_CPUCAP_OPTIONAL_FOR_LATE_CPU ((u16)BIT(5)) #define ARM64_CPUCAP_OPTIONAL_FOR_LATE_CPU ((u16)BIT(5))
/* Panic when a conflict is detected */
#define ARM64_CPUCAP_PANIC_ON_CONFLICT ((u16)BIT(6))
/* /*
* CPU errata workarounds that need to be enabled at boot time if one or * CPU errata workarounds that need to be enabled at boot time if one or
...@@ -279,9 +285,11 @@ extern struct arm64_ftr_reg arm64_ftr_reg_ctrel0; ...@@ -279,9 +285,11 @@ extern struct arm64_ftr_reg arm64_ftr_reg_ctrel0;
/* /*
* CPU feature used early in the boot based on the boot CPU. All secondary * CPU feature used early in the boot based on the boot CPU. All secondary
* CPUs must match the state of the capability as detected by the boot CPU. * CPUs must match the state of the capability as detected by the boot CPU. In
* case of a conflict, a kernel panic is triggered.
*/ */
#define ARM64_CPUCAP_STRICT_BOOT_CPU_FEATURE ARM64_CPUCAP_SCOPE_BOOT_CPU #define ARM64_CPUCAP_STRICT_BOOT_CPU_FEATURE \
(ARM64_CPUCAP_SCOPE_BOOT_CPU | ARM64_CPUCAP_PANIC_ON_CONFLICT)
struct arm64_cpu_capabilities { struct arm64_cpu_capabilities {
const char *desc; const char *desc;
......
...@@ -1376,6 +1376,12 @@ cpucap_late_cpu_permitted(const struct arm64_cpu_capabilities *cap) ...@@ -1376,6 +1376,12 @@ cpucap_late_cpu_permitted(const struct arm64_cpu_capabilities *cap)
return !!(cap->type & ARM64_CPUCAP_PERMITTED_FOR_LATE_CPU); return !!(cap->type & ARM64_CPUCAP_PERMITTED_FOR_LATE_CPU);
} }
static bool
cpucap_panic_on_conflict(const struct arm64_cpu_capabilities *cap)
{
return !!(cap->type & ARM64_CPUCAP_PANIC_ON_CONFLICT);
}
static const struct arm64_cpu_capabilities arm64_features[] = { static const struct arm64_cpu_capabilities arm64_features[] = {
{ {
.desc = "GIC system register CPU interface", .desc = "GIC system register CPU interface",
...@@ -2018,10 +2024,8 @@ static void __init enable_cpu_capabilities(u16 scope_mask) ...@@ -2018,10 +2024,8 @@ static void __init enable_cpu_capabilities(u16 scope_mask)
* Run through the list of capabilities to check for conflicts. * Run through the list of capabilities to check for conflicts.
* If the system has already detected a capability, take necessary * If the system has already detected a capability, take necessary
* action on this CPU. * action on this CPU.
*
* Returns "false" on conflicts.
*/ */
static bool verify_local_cpu_caps(u16 scope_mask) static void verify_local_cpu_caps(u16 scope_mask)
{ {
int i; int i;
bool cpu_has_cap, system_has_cap; bool cpu_has_cap, system_has_cap;
...@@ -2066,10 +2070,12 @@ static bool verify_local_cpu_caps(u16 scope_mask) ...@@ -2066,10 +2070,12 @@ static bool verify_local_cpu_caps(u16 scope_mask)
pr_crit("CPU%d: Detected conflict for capability %d (%s), System: %d, CPU: %d\n", pr_crit("CPU%d: Detected conflict for capability %d (%s), System: %d, CPU: %d\n",
smp_processor_id(), caps->capability, smp_processor_id(), caps->capability,
caps->desc, system_has_cap, cpu_has_cap); caps->desc, system_has_cap, cpu_has_cap);
return false;
}
return true; if (cpucap_panic_on_conflict(caps))
cpu_panic_kernel();
else
cpu_die_early();
}
} }
/* /*
...@@ -2079,12 +2085,8 @@ static bool verify_local_cpu_caps(u16 scope_mask) ...@@ -2079,12 +2085,8 @@ static bool verify_local_cpu_caps(u16 scope_mask)
static void check_early_cpu_features(void) static void check_early_cpu_features(void)
{ {
verify_cpu_asid_bits(); verify_cpu_asid_bits();
/*
* Early features are used by the kernel already. If there verify_local_cpu_caps(SCOPE_BOOT_CPU);
* is a conflict, we cannot proceed further.
*/
if (!verify_local_cpu_caps(SCOPE_BOOT_CPU))
cpu_panic_kernel();
} }
static void static void
...@@ -2132,8 +2134,7 @@ static void verify_local_cpu_capabilities(void) ...@@ -2132,8 +2134,7 @@ static void verify_local_cpu_capabilities(void)
* check_early_cpu_features(), as they need to be verified * check_early_cpu_features(), as they need to be verified
* on all secondary CPUs. * on all secondary CPUs.
*/ */
if (!verify_local_cpu_caps(SCOPE_ALL & ~SCOPE_BOOT_CPU)) verify_local_cpu_caps(SCOPE_ALL & ~SCOPE_BOOT_CPU);
cpu_die_early();
verify_local_elf_hwcaps(arm64_elf_hwcaps); verify_local_elf_hwcaps(arm64_elf_hwcaps);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment