|
@@ -235,6 +235,38 @@ enable_smccc_arch_workaround_1(const struct arm64_cpu_capabilities *entry)
|
|
|
#ifdef CONFIG_ARM64_SSBD
|
|
|
DEFINE_PER_CPU_READ_MOSTLY(u64, arm64_ssbd_callback_required);
|
|
|
|
|
|
+int ssbd_state __read_mostly = ARM64_SSBD_KERNEL;
|
|
|
+
|
|
|
+static const struct ssbd_options {
|
|
|
+ const char *str;
|
|
|
+ int state;
|
|
|
+} ssbd_options[] = {
|
|
|
+ { "force-on", ARM64_SSBD_FORCE_ENABLE, },
|
|
|
+ { "force-off", ARM64_SSBD_FORCE_DISABLE, },
|
|
|
+ { "kernel", ARM64_SSBD_KERNEL, },
|
|
|
+};
|
|
|
+
|
|
|
+static int __init ssbd_cfg(char *buf)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+
|
|
|
+ if (!buf || !buf[0])
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ for (i = 0; i < ARRAY_SIZE(ssbd_options); i++) {
|
|
|
+ int len = strlen(ssbd_options[i].str);
|
|
|
+
|
|
|
+ if (strncmp(buf, ssbd_options[i].str, len))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ ssbd_state = ssbd_options[i].state;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ return -EINVAL;
|
|
|
+}
|
|
|
+early_param("ssbd", ssbd_cfg);
|
|
|
+
|
|
|
void __init arm64_update_smccc_conduit(struct alt_instr *alt,
|
|
|
__le32 *origptr, __le32 *updptr,
|
|
|
int nr_inst)
|
|
@@ -278,44 +310,83 @@ static bool has_ssbd_mitigation(const struct arm64_cpu_capabilities *entry,
|
|
|
int scope)
|
|
|
{
|
|
|
struct arm_smccc_res res;
|
|
|
- bool supported = true;
|
|
|
+ bool required = true;
|
|
|
+ s32 val;
|
|
|
|
|
|
WARN_ON(scope != SCOPE_LOCAL_CPU || preemptible());
|
|
|
|
|
|
- if (psci_ops.smccc_version == SMCCC_VERSION_1_0)
|
|
|
+ if (psci_ops.smccc_version == SMCCC_VERSION_1_0) {
|
|
|
+ ssbd_state = ARM64_SSBD_UNKNOWN;
|
|
|
return false;
|
|
|
+ }
|
|
|
|
|
|
- /*
|
|
|
- * The probe function return value is either negative
|
|
|
- * (unsupported or mitigated), positive (unaffected), or zero
|
|
|
- * (requires mitigation). We only need to do anything in the
|
|
|
- * last case.
|
|
|
- */
|
|
|
switch (psci_ops.conduit) {
|
|
|
case PSCI_CONDUIT_HVC:
|
|
|
arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
|
|
|
ARM_SMCCC_ARCH_WORKAROUND_2, &res);
|
|
|
- if ((int)res.a0 != 0)
|
|
|
- supported = false;
|
|
|
break;
|
|
|
|
|
|
case PSCI_CONDUIT_SMC:
|
|
|
arm_smccc_1_1_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
|
|
|
ARM_SMCCC_ARCH_WORKAROUND_2, &res);
|
|
|
- if ((int)res.a0 != 0)
|
|
|
- supported = false;
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
- supported = false;
|
|
|
+ ssbd_state = ARM64_SSBD_UNKNOWN;
|
|
|
+ return false;
|
|
|
}
|
|
|
|
|
|
- if (supported) {
|
|
|
- __this_cpu_write(arm64_ssbd_callback_required, 1);
|
|
|
+ val = (s32)res.a0;
|
|
|
+
|
|
|
+ switch (val) {
|
|
|
+ case SMCCC_RET_NOT_SUPPORTED:
|
|
|
+ ssbd_state = ARM64_SSBD_UNKNOWN;
|
|
|
+ return false;
|
|
|
+
|
|
|
+ case SMCCC_RET_NOT_REQUIRED:
|
|
|
+ pr_info_once("%s mitigation not required\n", entry->desc);
|
|
|
+ ssbd_state = ARM64_SSBD_MITIGATED;
|
|
|
+ return false;
|
|
|
+
|
|
|
+ case SMCCC_RET_SUCCESS:
|
|
|
+ required = true;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 1: /* Mitigation not required on this CPU */
|
|
|
+ required = false;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ WARN_ON(1);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ switch (ssbd_state) {
|
|
|
+ case ARM64_SSBD_FORCE_DISABLE:
|
|
|
+ pr_info_once("%s disabled from command-line\n", entry->desc);
|
|
|
+ arm64_set_ssbd_mitigation(false);
|
|
|
+ required = false;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case ARM64_SSBD_KERNEL:
|
|
|
+ if (required) {
|
|
|
+ __this_cpu_write(arm64_ssbd_callback_required, 1);
|
|
|
+ arm64_set_ssbd_mitigation(true);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case ARM64_SSBD_FORCE_ENABLE:
|
|
|
+ pr_info_once("%s forced from command-line\n", entry->desc);
|
|
|
arm64_set_ssbd_mitigation(true);
|
|
|
+ required = true;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ WARN_ON(1);
|
|
|
+ break;
|
|
|
}
|
|
|
|
|
|
- return supported;
|
|
|
+ return required;
|
|
|
}
|
|
|
#endif /* CONFIG_ARM64_SSBD */
|
|
|
|