ARM: spectre-v2: add firmware based hardening
Add firmware based hardening for cores that require more complex handling in firmware. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> Boot-tested-by: Tony Lindgren <tony@atomide.com> Reviewed-by: Tony Lindgren <tony@atomide.com> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
This commit is contained in:
		
							parent
							
								
									f5fe12b1ea
								
							
						
					
					
						commit
						10115105cb
					
				| @ -1,14 +1,20 @@ | |||||||
| // SPDX-License-Identifier: GPL-2.0
 | // SPDX-License-Identifier: GPL-2.0
 | ||||||
|  | #include <linux/arm-smccc.h> | ||||||
| #include <linux/kernel.h> | #include <linux/kernel.h> | ||||||
|  | #include <linux/psci.h> | ||||||
| #include <linux/smp.h> | #include <linux/smp.h> | ||||||
| 
 | 
 | ||||||
| #include <asm/cp15.h> | #include <asm/cp15.h> | ||||||
| #include <asm/cputype.h> | #include <asm/cputype.h> | ||||||
|  | #include <asm/proc-fns.h> | ||||||
| #include <asm/system_misc.h> | #include <asm/system_misc.h> | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_HARDEN_BRANCH_PREDICTOR | #ifdef CONFIG_HARDEN_BRANCH_PREDICTOR | ||||||
| DEFINE_PER_CPU(harden_branch_predictor_fn_t, harden_branch_predictor_fn); | DEFINE_PER_CPU(harden_branch_predictor_fn_t, harden_branch_predictor_fn); | ||||||
| 
 | 
 | ||||||
|  | extern void cpu_v7_smc_switch_mm(phys_addr_t pgd_phys, struct mm_struct *mm); | ||||||
|  | extern void cpu_v7_hvc_switch_mm(phys_addr_t pgd_phys, struct mm_struct *mm); | ||||||
|  | 
 | ||||||
| static void harden_branch_predictor_bpiall(void) | static void harden_branch_predictor_bpiall(void) | ||||||
| { | { | ||||||
| 	write_sysreg(0, BPIALL); | 	write_sysreg(0, BPIALL); | ||||||
| @ -19,6 +25,16 @@ static void harden_branch_predictor_iciallu(void) | |||||||
| 	write_sysreg(0, ICIALLU); | 	write_sysreg(0, ICIALLU); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void __maybe_unused call_smc_arch_workaround_1(void) | ||||||
|  | { | ||||||
|  | 	arm_smccc_1_1_smc(ARM_SMCCC_ARCH_WORKAROUND_1, NULL); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void __maybe_unused call_hvc_arch_workaround_1(void) | ||||||
|  | { | ||||||
|  | 	arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_WORKAROUND_1, NULL); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static void cpu_v7_spectre_init(void) | static void cpu_v7_spectre_init(void) | ||||||
| { | { | ||||||
| 	const char *spectre_v2_method = NULL; | 	const char *spectre_v2_method = NULL; | ||||||
| @ -45,7 +61,51 @@ static void cpu_v7_spectre_init(void) | |||||||
| 			harden_branch_predictor_iciallu; | 			harden_branch_predictor_iciallu; | ||||||
| 		spectre_v2_method = "ICIALLU"; | 		spectre_v2_method = "ICIALLU"; | ||||||
| 		break; | 		break; | ||||||
|  | 
 | ||||||
|  | #ifdef CONFIG_ARM_PSCI | ||||||
|  | 	default: | ||||||
|  | 		/* Other ARM CPUs require no workaround */ | ||||||
|  | 		if (read_cpuid_implementor() == ARM_CPU_IMP_ARM) | ||||||
|  | 			break; | ||||||
|  | 		/* fallthrough */ | ||||||
|  | 		/* Cortex A57/A72 require firmware workaround */ | ||||||
|  | 	case ARM_CPU_PART_CORTEX_A57: | ||||||
|  | 	case ARM_CPU_PART_CORTEX_A72: { | ||||||
|  | 		struct arm_smccc_res res; | ||||||
|  | 
 | ||||||
|  | 		if (psci_ops.smccc_version == SMCCC_VERSION_1_0) | ||||||
|  | 			break; | ||||||
|  | 
 | ||||||
|  | 		switch (psci_ops.conduit) { | ||||||
|  | 		case PSCI_CONDUIT_HVC: | ||||||
|  | 			arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, | ||||||
|  | 					  ARM_SMCCC_ARCH_WORKAROUND_1, &res); | ||||||
|  | 			if ((int)res.a0 != 0) | ||||||
|  | 				break; | ||||||
|  | 			per_cpu(harden_branch_predictor_fn, cpu) = | ||||||
|  | 				call_hvc_arch_workaround_1; | ||||||
|  | 			processor.switch_mm = cpu_v7_hvc_switch_mm; | ||||||
|  | 			spectre_v2_method = "hypervisor"; | ||||||
|  | 			break; | ||||||
|  | 
 | ||||||
|  | 		case PSCI_CONDUIT_SMC: | ||||||
|  | 			arm_smccc_1_1_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, | ||||||
|  | 					  ARM_SMCCC_ARCH_WORKAROUND_1, &res); | ||||||
|  | 			if ((int)res.a0 != 0) | ||||||
|  | 				break; | ||||||
|  | 			per_cpu(harden_branch_predictor_fn, cpu) = | ||||||
|  | 				call_smc_arch_workaround_1; | ||||||
|  | 			processor.switch_mm = cpu_v7_smc_switch_mm; | ||||||
|  | 			spectre_v2_method = "firmware"; | ||||||
|  | 			break; | ||||||
|  | 
 | ||||||
|  | 		default: | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
|  | #endif | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	if (spectre_v2_method) | 	if (spectre_v2_method) | ||||||
| 		pr_info("CPU%u: Spectre v2: using %s workaround\n", | 		pr_info("CPU%u: Spectre v2: using %s workaround\n", | ||||||
| 			smp_processor_id(), spectre_v2_method); | 			smp_processor_id(), spectre_v2_method); | ||||||
|  | |||||||
| @ -9,6 +9,7 @@ | |||||||
|  * |  * | ||||||
|  *  This is the "shell" of the ARMv7 processor support. |  *  This is the "shell" of the ARMv7 processor support. | ||||||
|  */ |  */ | ||||||
|  | #include <linux/arm-smccc.h> | ||||||
| #include <linux/init.h> | #include <linux/init.h> | ||||||
| #include <linux/linkage.h> | #include <linux/linkage.h> | ||||||
| #include <asm/assembler.h> | #include <asm/assembler.h> | ||||||
| @ -93,6 +94,26 @@ ENTRY(cpu_v7_dcache_clean_area) | |||||||
| 	ret	lr | 	ret	lr | ||||||
| ENDPROC(cpu_v7_dcache_clean_area) | ENDPROC(cpu_v7_dcache_clean_area) | ||||||
| 
 | 
 | ||||||
|  | #ifdef CONFIG_ARM_PSCI | ||||||
|  | 	.arch_extension sec
 | ||||||
|  | ENTRY(cpu_v7_smc_switch_mm) | ||||||
|  | 	stmfd	sp!, {r0 - r3} | ||||||
|  | 	movw	r0, #:lower16:ARM_SMCCC_ARCH_WORKAROUND_1 | ||||||
|  | 	movt	r0, #:upper16:ARM_SMCCC_ARCH_WORKAROUND_1 | ||||||
|  | 	smc	#0 | ||||||
|  | 	ldmfd	sp!, {r0 - r3} | ||||||
|  | 	b	cpu_v7_switch_mm | ||||||
|  | ENDPROC(cpu_v7_smc_switch_mm) | ||||||
|  | 	.arch_extension virt
 | ||||||
|  | ENTRY(cpu_v7_hvc_switch_mm) | ||||||
|  | 	stmfd	sp!, {r0 - r3} | ||||||
|  | 	movw	r0, #:lower16:ARM_SMCCC_ARCH_WORKAROUND_1 | ||||||
|  | 	movt	r0, #:upper16:ARM_SMCCC_ARCH_WORKAROUND_1 | ||||||
|  | 	hvc	#0 | ||||||
|  | 	ldmfd	sp!, {r0 - r3} | ||||||
|  | 	b	cpu_v7_switch_mm | ||||||
|  | ENDPROC(cpu_v7_smc_switch_mm) | ||||||
|  | #endif | ||||||
| ENTRY(cpu_v7_iciallu_switch_mm) | ENTRY(cpu_v7_iciallu_switch_mm) | ||||||
| 	mov	r3, #0 | 	mov	r3, #0 | ||||||
| 	mcr	p15, 0, r3, c7, c5, 0		@ ICIALLU
 | 	mcr	p15, 0, r3, c7, c5, 0		@ ICIALLU
 | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user