mirror of
https://github.com/armbian/build
synced 2025-09-24 19:47:06 +07:00
2262 lines
72 KiB
Diff
2262 lines
72 KiB
Diff
diff --git a/Makefile b/Makefile
|
|
index bd3bdf86b992e..f9054b4e8a123 100644
|
|
--- a/Makefile
|
|
+++ b/Makefile
|
|
@@ -1,7 +1,7 @@
|
|
# SPDX-License-Identifier: GPL-2.0
|
|
VERSION = 5
|
|
PATCHLEVEL = 4
|
|
-SUBLEVEL = 185
|
|
+SUBLEVEL = 186
|
|
EXTRAVERSION =
|
|
NAME = Kleptomaniac Octopus
|
|
|
|
diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi
|
|
index 140e22d74dcfb..d393bb481e747 100644
|
|
--- a/arch/arm/boot/dts/rk322x.dtsi
|
|
+++ b/arch/arm/boot/dts/rk322x.dtsi
|
|
@@ -635,8 +635,8 @@
|
|
interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
|
|
assigned-clocks = <&cru SCLK_HDMI_PHY>;
|
|
assigned-clock-parents = <&hdmi_phy>;
|
|
- clocks = <&cru SCLK_HDMI_HDCP>, <&cru PCLK_HDMI_CTRL>, <&cru SCLK_HDMI_CEC>;
|
|
- clock-names = "isfr", "iahb", "cec";
|
|
+ clocks = <&cru PCLK_HDMI_CTRL>, <&cru SCLK_HDMI_HDCP>, <&cru SCLK_HDMI_CEC>;
|
|
+ clock-names = "iahb", "isfr", "cec";
|
|
pinctrl-names = "default";
|
|
pinctrl-0 = <&hdmii2c_xfer &hdmi_hpd &hdmi_cec>;
|
|
resets = <&cru SRST_HDMI_P>;
|
|
diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
|
|
index 658ceb96d8bd1..7dcafd0833ba8 100644
|
|
--- a/arch/arm/boot/dts/rk3288.dtsi
|
|
+++ b/arch/arm/boot/dts/rk3288.dtsi
|
|
@@ -975,7 +975,7 @@
|
|
status = "disabled";
|
|
};
|
|
|
|
- crypto: cypto-controller@ff8a0000 {
|
|
+ crypto: crypto@ff8a0000 {
|
|
compatible = "rockchip,rk3288-crypto";
|
|
reg = <0x0 0xff8a0000 0x0 0x4000>;
|
|
interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
|
|
diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
|
|
index 32564b017ba06..d8ac89879327d 100644
|
|
--- a/arch/arm/include/asm/kvm_host.h
|
|
+++ b/arch/arm/include/asm/kvm_host.h
|
|
@@ -15,6 +15,7 @@
|
|
#include <asm/kvm_asm.h>
|
|
#include <asm/kvm_mmio.h>
|
|
#include <asm/fpstate.h>
|
|
+#include <asm/spectre.h>
|
|
#include <kvm/arm_arch_timer.h>
|
|
|
|
#define __KVM_HAVE_ARCH_INTC_INITIALIZED
|
|
@@ -424,4 +425,10 @@ static inline bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu)
|
|
|
|
#define kvm_arm_vcpu_loaded(vcpu) (false)
|
|
|
|
+static inline int kvm_arm_get_spectre_bhb_state(void)
|
|
+{
|
|
+ /* 32bit guests don't need firmware for this */
|
|
+ return SPECTRE_VULNERABLE; /* aka SMCCC_RET_NOT_SUPPORTED */
|
|
+}
|
|
+
|
|
#endif /* __ARM_KVM_HOST_H__ */
|
|
diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
|
|
index 2769360f195ca..89b8e70068a13 100644
|
|
--- a/arch/arm/include/uapi/asm/kvm.h
|
|
+++ b/arch/arm/include/uapi/asm/kvm.h
|
|
@@ -227,6 +227,12 @@ struct kvm_vcpu_events {
|
|
#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED 3
|
|
#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED (1U << 4)
|
|
|
|
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3 KVM_REG_ARM_FW_REG(3)
|
|
+ /* Higher values mean better protection. */
|
|
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL 0
|
|
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_AVAIL 1
|
|
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_REQUIRED 2
|
|
+
|
|
/* Device Control API: ARM VGIC */
|
|
#define KVM_DEV_ARM_VGIC_GRP_ADDR 0
|
|
#define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1
|
|
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
|
|
index 9c8ea59398658..a1a828ca188cf 100644
|
|
--- a/arch/arm64/Kconfig
|
|
+++ b/arch/arm64/Kconfig
|
|
@@ -1139,6 +1139,15 @@ config ARM64_SSBD
|
|
|
|
If unsure, say Y.
|
|
|
|
+config MITIGATE_SPECTRE_BRANCH_HISTORY
|
|
+ bool "Mitigate Spectre style attacks against branch history" if EXPERT
|
|
+ default y
|
|
+ help
|
|
+ Speculation attacks against some high-performance processors can
|
|
+ make use of branch history to influence future speculation.
|
|
+ When taking an exception from user-space, a sequence of branches
|
|
+ or a firmware call overwrites the branch history.
|
|
+
|
|
config RODATA_FULL_DEFAULT_ENABLED
|
|
bool "Apply r/o permissions of VM areas also to their linear aliases"
|
|
default y
|
|
diff --git a/arch/arm64/boot/dts/intel/socfpga_agilex.dtsi b/arch/arm64/boot/dts/intel/socfpga_agilex.dtsi
|
|
index d911d38877e52..19f17bb29e4bd 100644
|
|
--- a/arch/arm64/boot/dts/intel/socfpga_agilex.dtsi
|
|
+++ b/arch/arm64/boot/dts/intel/socfpga_agilex.dtsi
|
|
@@ -369,7 +369,7 @@
|
|
};
|
|
|
|
usb0: usb@ffb00000 {
|
|
- compatible = "snps,dwc2";
|
|
+ compatible = "intel,socfpga-agilex-hsotg", "snps,dwc2";
|
|
reg = <0xffb00000 0x40000>;
|
|
interrupts = <0 93 4>;
|
|
phys = <&usbphy0>;
|
|
@@ -381,7 +381,7 @@
|
|
};
|
|
|
|
usb1: usb@ffb40000 {
|
|
- compatible = "snps,dwc2";
|
|
+ compatible = "intel,socfpga-agilex-hsotg", "snps,dwc2";
|
|
reg = <0xffb40000 0x40000>;
|
|
interrupts = <0 94 4>;
|
|
phys = <&usbphy0>;
|
|
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi
|
|
index 45b86933c6ea0..390b86ec65389 100644
|
|
--- a/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi
|
|
+++ b/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi
|
|
@@ -467,6 +467,12 @@
|
|
};
|
|
|
|
&sdhci {
|
|
+ /*
|
|
+ * Signal integrity isn't great at 200MHz but 100MHz has proven stable
|
|
+ * enough.
|
|
+ */
|
|
+ max-frequency = <100000000>;
|
|
+
|
|
bus-width = <8>;
|
|
mmc-hs400-1_8v;
|
|
mmc-hs400-enhanced-strobe;
|
|
diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
|
|
index 750dad0d17400..95942d917de53 100644
|
|
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
|
|
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
|
|
@@ -1746,10 +1746,10 @@
|
|
interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH 0>;
|
|
clocks = <&cru PCLK_HDMI_CTRL>,
|
|
<&cru SCLK_HDMI_SFR>,
|
|
- <&cru PLL_VPLL>,
|
|
+ <&cru SCLK_HDMI_CEC>,
|
|
<&cru PCLK_VIO_GRF>,
|
|
- <&cru SCLK_HDMI_CEC>;
|
|
- clock-names = "iahb", "isfr", "vpll", "grf", "cec";
|
|
+ <&cru PLL_VPLL>;
|
|
+ clock-names = "iahb", "isfr", "cec", "grf", "vpll";
|
|
power-domains = <&power RK3399_PD_HDCP>;
|
|
reg-io-width = <4>;
|
|
rockchip,grf = <&grf>;
|
|
diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
|
|
index 4a4258f17c868..01112f9767bc3 100644
|
|
--- a/arch/arm64/include/asm/assembler.h
|
|
+++ b/arch/arm64/include/asm/assembler.h
|
|
@@ -110,6 +110,13 @@
|
|
hint #20
|
|
.endm
|
|
|
|
+/*
|
|
+ * Clear Branch History instruction
|
|
+ */
|
|
+ .macro clearbhb
|
|
+ hint #22
|
|
+ .endm
|
|
+
|
|
/*
|
|
* Speculation barrier
|
|
*/
|
|
@@ -757,4 +764,30 @@ USER(\label, ic ivau, \tmp2) // invalidate I line PoU
|
|
.Lyield_out_\@ :
|
|
.endm
|
|
|
|
+ .macro __mitigate_spectre_bhb_loop tmp
|
|
+#ifdef CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY
|
|
+alternative_cb spectre_bhb_patch_loop_iter
|
|
+ mov \tmp, #32 // Patched to correct the immediate
|
|
+alternative_cb_end
|
|
+.Lspectre_bhb_loop\@:
|
|
+ b . + 4
|
|
+ subs \tmp, \tmp, #1
|
|
+ b.ne .Lspectre_bhb_loop\@
|
|
+ sb
|
|
+#endif /* CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY */
|
|
+ .endm
|
|
+
|
|
+ /* Save/restores x0-x3 to the stack */
|
|
+ .macro __mitigate_spectre_bhb_fw
|
|
+#ifdef CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY
|
|
+ stp x0, x1, [sp, #-16]!
|
|
+ stp x2, x3, [sp, #-16]!
|
|
+ mov w0, #ARM_SMCCC_ARCH_WORKAROUND_3
|
|
+alternative_cb arm64_update_smccc_conduit
|
|
+ nop // Patched to SMC/HVC #0
|
|
+alternative_cb_end
|
|
+ ldp x2, x3, [sp], #16
|
|
+ ldp x0, x1, [sp], #16
|
|
+#endif /* CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY */
|
|
+ .endm
|
|
#endif /* __ASM_ASSEMBLER_H */
|
|
diff --git a/arch/arm64/include/asm/cpu.h b/arch/arm64/include/asm/cpu.h
|
|
index d72d995b7e258..85cc06380e93e 100644
|
|
--- a/arch/arm64/include/asm/cpu.h
|
|
+++ b/arch/arm64/include/asm/cpu.h
|
|
@@ -25,6 +25,7 @@ struct cpuinfo_arm64 {
|
|
u64 reg_id_aa64dfr1;
|
|
u64 reg_id_aa64isar0;
|
|
u64 reg_id_aa64isar1;
|
|
+ u64 reg_id_aa64isar2;
|
|
u64 reg_id_aa64mmfr0;
|
|
u64 reg_id_aa64mmfr1;
|
|
u64 reg_id_aa64mmfr2;
|
|
diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h
|
|
index 1dc3c762fdcb9..4ffa86149d28d 100644
|
|
--- a/arch/arm64/include/asm/cpucaps.h
|
|
+++ b/arch/arm64/include/asm/cpucaps.h
|
|
@@ -55,7 +55,8 @@
|
|
#define ARM64_WORKAROUND_CAVIUM_TX2_219_TVM 45
|
|
#define ARM64_WORKAROUND_CAVIUM_TX2_219_PRFM 46
|
|
#define ARM64_WORKAROUND_1542419 47
|
|
+#define ARM64_SPECTRE_BHB 48
|
|
|
|
-#define ARM64_NCAPS 48
|
|
+#define ARM64_NCAPS 49
|
|
|
|
#endif /* __ASM_CPUCAPS_H */
|
|
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
|
|
index ccae05da98a7f..f63438474dd54 100644
|
|
--- a/arch/arm64/include/asm/cpufeature.h
|
|
+++ b/arch/arm64/include/asm/cpufeature.h
|
|
@@ -508,6 +508,34 @@ static inline bool cpu_supports_mixed_endian_el0(void)
|
|
return id_aa64mmfr0_mixed_endian_el0(read_cpuid(ID_AA64MMFR0_EL1));
|
|
}
|
|
|
|
+static inline bool supports_csv2p3(int scope)
|
|
+{
|
|
+ u64 pfr0;
|
|
+ u8 csv2_val;
|
|
+
|
|
+ if (scope == SCOPE_LOCAL_CPU)
|
|
+ pfr0 = read_sysreg_s(SYS_ID_AA64PFR0_EL1);
|
|
+ else
|
|
+ pfr0 = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1);
|
|
+
|
|
+ csv2_val = cpuid_feature_extract_unsigned_field(pfr0,
|
|
+ ID_AA64PFR0_CSV2_SHIFT);
|
|
+ return csv2_val == 3;
|
|
+}
|
|
+
|
|
+static inline bool supports_clearbhb(int scope)
|
|
+{
|
|
+ u64 isar2;
|
|
+
|
|
+ if (scope == SCOPE_LOCAL_CPU)
|
|
+ isar2 = read_sysreg_s(SYS_ID_AA64ISAR2_EL1);
|
|
+ else
|
|
+ isar2 = read_sanitised_ftr_reg(SYS_ID_AA64ISAR2_EL1);
|
|
+
|
|
+ return cpuid_feature_extract_unsigned_field(isar2,
|
|
+ ID_AA64ISAR2_CLEARBHB_SHIFT);
|
|
+}
|
|
+
|
|
static inline bool system_supports_32bit_el0(void)
|
|
{
|
|
return cpus_have_const_cap(ARM64_HAS_32BIT_EL0);
|
|
@@ -639,6 +667,18 @@ static inline int arm64_get_ssbd_state(void)
|
|
|
|
void arm64_set_ssbd_mitigation(bool state);
|
|
|
|
+/* Watch out, ordering is important here. */
|
|
+enum mitigation_state {
|
|
+ SPECTRE_UNAFFECTED,
|
|
+ SPECTRE_MITIGATED,
|
|
+ SPECTRE_VULNERABLE,
|
|
+};
|
|
+
|
|
+enum mitigation_state arm64_get_spectre_bhb_state(void);
|
|
+bool is_spectre_bhb_affected(const struct arm64_cpu_capabilities *entry, int scope);
|
|
+u8 spectre_bhb_loop_affected(int scope);
|
|
+void spectre_bhb_enable_mitigation(const struct arm64_cpu_capabilities *__unused);
|
|
+
|
|
extern int do_emulate_mrs(struct pt_regs *regs, u32 sys_reg, u32 rt);
|
|
|
|
static inline u32 id_aa64mmfr0_parange_to_phys_shift(int parange)
|
|
diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h
|
|
index aca07c2f6e6e3..f0165df489a38 100644
|
|
--- a/arch/arm64/include/asm/cputype.h
|
|
+++ b/arch/arm64/include/asm/cputype.h
|
|
@@ -71,6 +71,14 @@
|
|
#define ARM_CPU_PART_CORTEX_A55 0xD05
|
|
#define ARM_CPU_PART_CORTEX_A76 0xD0B
|
|
#define ARM_CPU_PART_NEOVERSE_N1 0xD0C
|
|
+#define ARM_CPU_PART_CORTEX_A77 0xD0D
|
|
+#define ARM_CPU_PART_NEOVERSE_V1 0xD40
|
|
+#define ARM_CPU_PART_CORTEX_A78 0xD41
|
|
+#define ARM_CPU_PART_CORTEX_X1 0xD44
|
|
+#define ARM_CPU_PART_CORTEX_A710 0xD47
|
|
+#define ARM_CPU_PART_CORTEX_X2 0xD48
|
|
+#define ARM_CPU_PART_NEOVERSE_N2 0xD49
|
|
+#define ARM_CPU_PART_CORTEX_A78C 0xD4B
|
|
|
|
#define APM_CPU_PART_POTENZA 0x000
|
|
|
|
@@ -102,6 +110,14 @@
|
|
#define MIDR_CORTEX_A55 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A55)
|
|
#define MIDR_CORTEX_A76 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A76)
|
|
#define MIDR_NEOVERSE_N1 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_N1)
|
|
+#define MIDR_CORTEX_A77 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A77)
|
|
+#define MIDR_NEOVERSE_V1 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_V1)
|
|
+#define MIDR_CORTEX_A78 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A78)
|
|
+#define MIDR_CORTEX_X1 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X1)
|
|
+#define MIDR_CORTEX_A710 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A710)
|
|
+#define MIDR_CORTEX_X2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X2)
|
|
+#define MIDR_NEOVERSE_N2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_N2)
|
|
+#define MIDR_CORTEX_A78C MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A78C)
|
|
#define MIDR_THUNDERX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX)
|
|
#define MIDR_THUNDERX_81XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_81XX)
|
|
#define MIDR_THUNDERX_83XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_83XX)
|
|
diff --git a/arch/arm64/include/asm/fixmap.h b/arch/arm64/include/asm/fixmap.h
|
|
index f987b8a8f325e..928a96b9b1617 100644
|
|
--- a/arch/arm64/include/asm/fixmap.h
|
|
+++ b/arch/arm64/include/asm/fixmap.h
|
|
@@ -63,9 +63,11 @@ enum fixed_addresses {
|
|
#endif /* CONFIG_ACPI_APEI_GHES */
|
|
|
|
#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
|
|
+ FIX_ENTRY_TRAMP_TEXT3,
|
|
+ FIX_ENTRY_TRAMP_TEXT2,
|
|
+ FIX_ENTRY_TRAMP_TEXT1,
|
|
FIX_ENTRY_TRAMP_DATA,
|
|
- FIX_ENTRY_TRAMP_TEXT,
|
|
-#define TRAMP_VALIAS (__fix_to_virt(FIX_ENTRY_TRAMP_TEXT))
|
|
+#define TRAMP_VALIAS (__fix_to_virt(FIX_ENTRY_TRAMP_TEXT1))
|
|
#endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */
|
|
__end_of_permanent_fixed_addresses,
|
|
|
|
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
|
|
index 697702a1a1ff1..e6efdbe88c0a9 100644
|
|
--- a/arch/arm64/include/asm/kvm_host.h
|
|
+++ b/arch/arm64/include/asm/kvm_host.h
|
|
@@ -684,4 +684,9 @@ bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu);
|
|
|
|
#define kvm_arm_vcpu_loaded(vcpu) ((vcpu)->arch.sysregs_loaded_on_cpu)
|
|
|
|
+static inline enum mitigation_state kvm_arm_get_spectre_bhb_state(void)
|
|
+{
|
|
+ return arm64_get_spectre_bhb_state();
|
|
+}
|
|
+
|
|
#endif /* __ARM64_KVM_HOST_H__ */
|
|
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
|
|
index befe37d4bc0e5..78d110667c0c7 100644
|
|
--- a/arch/arm64/include/asm/kvm_mmu.h
|
|
+++ b/arch/arm64/include/asm/kvm_mmu.h
|
|
@@ -478,7 +478,8 @@ static inline void *kvm_get_hyp_vector(void)
|
|
void *vect = kern_hyp_va(kvm_ksym_ref(__kvm_hyp_vector));
|
|
int slot = -1;
|
|
|
|
- if (cpus_have_const_cap(ARM64_HARDEN_BRANCH_PREDICTOR) && data->fn) {
|
|
+ if ((cpus_have_const_cap(ARM64_HARDEN_BRANCH_PREDICTOR) ||
|
|
+ cpus_have_const_cap(ARM64_SPECTRE_BHB)) && data->template_start) {
|
|
vect = kern_hyp_va(kvm_ksym_ref(__bp_harden_hyp_vecs_start));
|
|
slot = data->hyp_vectors_slot;
|
|
}
|
|
@@ -507,7 +508,8 @@ static inline int kvm_map_vectors(void)
|
|
* !HBP + HEL2 -> allocate one vector slot and use exec mapping
|
|
* HBP + HEL2 -> use hardened vertors and use exec mapping
|
|
*/
|
|
- if (cpus_have_const_cap(ARM64_HARDEN_BRANCH_PREDICTOR)) {
|
|
+ if (cpus_have_const_cap(ARM64_HARDEN_BRANCH_PREDICTOR) ||
|
|
+ cpus_have_const_cap(ARM64_SPECTRE_BHB)) {
|
|
__kvm_bp_vect_base = kvm_ksym_ref(__bp_harden_hyp_vecs_start);
|
|
__kvm_bp_vect_base = kern_hyp_va(__kvm_bp_vect_base);
|
|
}
|
|
diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h
|
|
index f217e32929193..1b9e49fb0e1b7 100644
|
|
--- a/arch/arm64/include/asm/mmu.h
|
|
+++ b/arch/arm64/include/asm/mmu.h
|
|
@@ -29,7 +29,7 @@ typedef struct {
|
|
*/
|
|
#define ASID(mm) ((mm)->context.id.counter & 0xffff)
|
|
|
|
-static inline bool arm64_kernel_unmapped_at_el0(void)
|
|
+static __always_inline bool arm64_kernel_unmapped_at_el0(void)
|
|
{
|
|
return IS_ENABLED(CONFIG_UNMAP_KERNEL_AT_EL0) &&
|
|
cpus_have_const_cap(ARM64_UNMAP_KERNEL_AT_EL0);
|
|
@@ -82,6 +82,12 @@ typedef void (*bp_hardening_cb_t)(void);
|
|
struct bp_hardening_data {
|
|
int hyp_vectors_slot;
|
|
bp_hardening_cb_t fn;
|
|
+
|
|
+ /*
|
|
+ * template_start is only used by the BHB mitigation to identify the
|
|
+ * hyp_vectors_slot sequence.
|
|
+ */
|
|
+ const char *template_start;
|
|
};
|
|
|
|
#if (defined(CONFIG_HARDEN_BRANCH_PREDICTOR) || \
|
|
diff --git a/arch/arm64/include/asm/sections.h b/arch/arm64/include/asm/sections.h
|
|
index 25a73aab438f9..a75f2882cc7cb 100644
|
|
--- a/arch/arm64/include/asm/sections.h
|
|
+++ b/arch/arm64/include/asm/sections.h
|
|
@@ -20,4 +20,9 @@ extern char __irqentry_text_start[], __irqentry_text_end[];
|
|
extern char __mmuoff_data_start[], __mmuoff_data_end[];
|
|
extern char __entry_tramp_text_start[], __entry_tramp_text_end[];
|
|
|
|
+static inline size_t entry_tramp_text_size(void)
|
|
+{
|
|
+ return __entry_tramp_text_end - __entry_tramp_text_start;
|
|
+}
|
|
+
|
|
#endif /* __ASM_SECTIONS_H */
|
|
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
|
|
index 9b68f1b3915ec..5b3bdad66b27e 100644
|
|
--- a/arch/arm64/include/asm/sysreg.h
|
|
+++ b/arch/arm64/include/asm/sysreg.h
|
|
@@ -165,6 +165,7 @@
|
|
|
|
#define SYS_ID_AA64ISAR0_EL1 sys_reg(3, 0, 0, 6, 0)
|
|
#define SYS_ID_AA64ISAR1_EL1 sys_reg(3, 0, 0, 6, 1)
|
|
+#define SYS_ID_AA64ISAR2_EL1 sys_reg(3, 0, 0, 6, 2)
|
|
|
|
#define SYS_ID_AA64MMFR0_EL1 sys_reg(3, 0, 0, 7, 0)
|
|
#define SYS_ID_AA64MMFR1_EL1 sys_reg(3, 0, 0, 7, 1)
|
|
@@ -575,6 +576,21 @@
|
|
#define ID_AA64ISAR1_GPI_NI 0x0
|
|
#define ID_AA64ISAR1_GPI_IMP_DEF 0x1
|
|
|
|
+/* id_aa64isar2 */
|
|
+#define ID_AA64ISAR2_CLEARBHB_SHIFT 28
|
|
+#define ID_AA64ISAR2_RPRES_SHIFT 4
|
|
+#define ID_AA64ISAR2_WFXT_SHIFT 0
|
|
+
|
|
+#define ID_AA64ISAR2_RPRES_8BIT 0x0
|
|
+#define ID_AA64ISAR2_RPRES_12BIT 0x1
|
|
+/*
|
|
+ * Value 0x1 has been removed from the architecture, and is
|
|
+ * reserved, but has not yet been removed from the ARM ARM
|
|
+ * as of ARM DDI 0487G.b.
|
|
+ */
|
|
+#define ID_AA64ISAR2_WFXT_NI 0x0
|
|
+#define ID_AA64ISAR2_WFXT_SUPPORTED 0x2
|
|
+
|
|
/* id_aa64pfr0 */
|
|
#define ID_AA64PFR0_CSV3_SHIFT 60
|
|
#define ID_AA64PFR0_CSV2_SHIFT 56
|
|
@@ -646,6 +662,7 @@
|
|
#endif
|
|
|
|
/* id_aa64mmfr1 */
|
|
+#define ID_AA64MMFR1_ECBHB_SHIFT 60
|
|
#define ID_AA64MMFR1_PAN_SHIFT 20
|
|
#define ID_AA64MMFR1_LOR_SHIFT 16
|
|
#define ID_AA64MMFR1_HPD_SHIFT 12
|
|
diff --git a/arch/arm64/include/asm/vectors.h b/arch/arm64/include/asm/vectors.h
|
|
new file mode 100644
|
|
index 0000000000000..f64613a96d530
|
|
--- /dev/null
|
|
+++ b/arch/arm64/include/asm/vectors.h
|
|
@@ -0,0 +1,73 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0-only */
|
|
+/*
|
|
+ * Copyright (C) 2022 ARM Ltd.
|
|
+ */
|
|
+#ifndef __ASM_VECTORS_H
|
|
+#define __ASM_VECTORS_H
|
|
+
|
|
+#include <linux/bug.h>
|
|
+#include <linux/percpu.h>
|
|
+
|
|
+#include <asm/fixmap.h>
|
|
+
|
|
+extern char vectors[];
|
|
+extern char tramp_vectors[];
|
|
+extern char __bp_harden_el1_vectors[];
|
|
+
|
|
+/*
|
|
+ * Note: the order of this enum corresponds to two arrays in entry.S:
|
|
+ * tramp_vecs and __bp_harden_el1_vectors. By default the canonical
|
|
+ * 'full fat' vectors are used directly.
|
|
+ */
|
|
+enum arm64_bp_harden_el1_vectors {
|
|
+#ifdef CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY
|
|
+ /*
|
|
+ * Perform the BHB loop mitigation, before branching to the canonical
|
|
+ * vectors.
|
|
+ */
|
|
+ EL1_VECTOR_BHB_LOOP,
|
|
+
|
|
+ /*
|
|
+ * Make the SMC call for firmware mitigation, before branching to the
|
|
+ * canonical vectors.
|
|
+ */
|
|
+ EL1_VECTOR_BHB_FW,
|
|
+
|
|
+ /*
|
|
+ * Use the ClearBHB instruction, before branching to the canonical
|
|
+ * vectors.
|
|
+ */
|
|
+ EL1_VECTOR_BHB_CLEAR_INSN,
|
|
+#endif /* CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY */
|
|
+
|
|
+ /*
|
|
+ * Remap the kernel before branching to the canonical vectors.
|
|
+ */
|
|
+ EL1_VECTOR_KPTI,
|
|
+};
|
|
+
|
|
+#ifndef CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY
|
|
+#define EL1_VECTOR_BHB_LOOP -1
|
|
+#define EL1_VECTOR_BHB_FW -1
|
|
+#define EL1_VECTOR_BHB_CLEAR_INSN -1
|
|
+#endif /* !CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY */
|
|
+
|
|
+/* The vectors to use on return from EL0. e.g. to remap the kernel */
|
|
+DECLARE_PER_CPU_READ_MOSTLY(const char *, this_cpu_vector);
|
|
+
|
|
+#ifndef CONFIG_UNMAP_KERNEL_AT_EL0
|
|
+#define TRAMP_VALIAS 0
|
|
+#endif
|
|
+
|
|
+static inline const char *
|
|
+arm64_get_bp_hardening_vector(enum arm64_bp_harden_el1_vectors slot)
|
|
+{
|
|
+ if (arm64_kernel_unmapped_at_el0())
|
|
+ return (char *)TRAMP_VALIAS + SZ_2K * slot;
|
|
+
|
|
+ WARN_ON_ONCE(slot == EL1_VECTOR_KPTI);
|
|
+
|
|
+ return __bp_harden_el1_vectors + SZ_2K * slot;
|
|
+}
|
|
+
|
|
+#endif /* __ASM_VECTORS_H */
|
|
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
|
|
index 67c21f9bdbad2..08440ce57a1c2 100644
|
|
--- a/arch/arm64/include/uapi/asm/kvm.h
|
|
+++ b/arch/arm64/include/uapi/asm/kvm.h
|
|
@@ -240,6 +240,11 @@ struct kvm_vcpu_events {
|
|
#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED 3
|
|
#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED (1U << 4)
|
|
|
|
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3 KVM_REG_ARM_FW_REG(3)
|
|
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL 0
|
|
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_AVAIL 1
|
|
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_REQUIRED 2
|
|
+
|
|
/* SVE registers */
|
|
#define KVM_REG_ARM64_SVE (0x15 << KVM_REG_ARM_COPROC_SHIFT)
|
|
|
|
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
|
|
index 1e16c4e00e771..33b33416fea42 100644
|
|
--- a/arch/arm64/kernel/cpu_errata.c
|
|
+++ b/arch/arm64/kernel/cpu_errata.c
|
|
@@ -13,6 +13,7 @@
|
|
#include <asm/cputype.h>
|
|
#include <asm/cpufeature.h>
|
|
#include <asm/smp_plat.h>
|
|
+#include <asm/vectors.h>
|
|
|
|
static bool __maybe_unused
|
|
is_affected_midr_range(const struct arm64_cpu_capabilities *entry, int scope)
|
|
@@ -116,6 +117,16 @@ DEFINE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data);
|
|
#ifdef CONFIG_KVM_INDIRECT_VECTORS
|
|
extern char __smccc_workaround_1_smc_start[];
|
|
extern char __smccc_workaround_1_smc_end[];
|
|
+extern char __smccc_workaround_3_smc_start[];
|
|
+extern char __smccc_workaround_3_smc_end[];
|
|
+extern char __spectre_bhb_loop_k8_start[];
|
|
+extern char __spectre_bhb_loop_k8_end[];
|
|
+extern char __spectre_bhb_loop_k24_start[];
|
|
+extern char __spectre_bhb_loop_k24_end[];
|
|
+extern char __spectre_bhb_loop_k32_start[];
|
|
+extern char __spectre_bhb_loop_k32_end[];
|
|
+extern char __spectre_bhb_clearbhb_start[];
|
|
+extern char __spectre_bhb_clearbhb_end[];
|
|
|
|
static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start,
|
|
const char *hyp_vecs_end)
|
|
@@ -129,11 +140,11 @@ static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start,
|
|
__flush_icache_range((uintptr_t)dst, (uintptr_t)dst + SZ_2K);
|
|
}
|
|
|
|
+static DEFINE_RAW_SPINLOCK(bp_lock);
|
|
static void install_bp_hardening_cb(bp_hardening_cb_t fn,
|
|
const char *hyp_vecs_start,
|
|
const char *hyp_vecs_end)
|
|
{
|
|
- static DEFINE_RAW_SPINLOCK(bp_lock);
|
|
int cpu, slot = -1;
|
|
|
|
/*
|
|
@@ -161,6 +172,7 @@ static void install_bp_hardening_cb(bp_hardening_cb_t fn,
|
|
|
|
__this_cpu_write(bp_hardening_data.hyp_vectors_slot, slot);
|
|
__this_cpu_write(bp_hardening_data.fn, fn);
|
|
+ __this_cpu_write(bp_hardening_data.template_start, hyp_vecs_start);
|
|
raw_spin_unlock(&bp_lock);
|
|
}
|
|
#else
|
|
@@ -927,6 +939,13 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
|
|
.cpu_enable = cpu_enable_ssbd_mitigation,
|
|
.midr_range_list = arm64_ssb_cpus,
|
|
},
|
|
+ {
|
|
+ .desc = "Spectre-BHB",
|
|
+ .capability = ARM64_SPECTRE_BHB,
|
|
+ .type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM,
|
|
+ .matches = is_spectre_bhb_affected,
|
|
+ .cpu_enable = spectre_bhb_enable_mitigation,
|
|
+ },
|
|
#ifdef CONFIG_ARM64_ERRATUM_1418040
|
|
{
|
|
.desc = "ARM erratum 1418040",
|
|
@@ -989,15 +1008,41 @@ ssize_t cpu_show_spectre_v1(struct device *dev, struct device_attribute *attr,
|
|
return sprintf(buf, "Mitigation: __user pointer sanitization\n");
|
|
}
|
|
|
|
+static const char *get_bhb_affected_string(enum mitigation_state bhb_state)
|
|
+{
|
|
+ switch (bhb_state) {
|
|
+ case SPECTRE_UNAFFECTED:
|
|
+ return "";
|
|
+ default:
|
|
+ case SPECTRE_VULNERABLE:
|
|
+ return ", but not BHB";
|
|
+ case SPECTRE_MITIGATED:
|
|
+ return ", BHB";
|
|
+ }
|
|
+}
|
|
+
|
|
ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
+ enum mitigation_state bhb_state = arm64_get_spectre_bhb_state();
|
|
+ const char *bhb_str = get_bhb_affected_string(bhb_state);
|
|
+ const char *v2_str = "Branch predictor hardening";
|
|
+
|
|
switch (get_spectre_v2_workaround_state()) {
|
|
case ARM64_BP_HARDEN_NOT_REQUIRED:
|
|
- return sprintf(buf, "Not affected\n");
|
|
- case ARM64_BP_HARDEN_WA_NEEDED:
|
|
- return sprintf(buf, "Mitigation: Branch predictor hardening\n");
|
|
- case ARM64_BP_HARDEN_UNKNOWN:
|
|
+ if (bhb_state == SPECTRE_UNAFFECTED)
|
|
+ return sprintf(buf, "Not affected\n");
|
|
+
|
|
+ /*
|
|
+ * Platforms affected by Spectre-BHB can't report
|
|
+ * "Not affected" for Spectre-v2.
|
|
+ */
|
|
+ v2_str = "CSV2";
|
|
+ fallthrough;
|
|
+ case ARM64_BP_HARDEN_WA_NEEDED:
|
|
+ return sprintf(buf, "Mitigation: %s%s\n", v2_str, bhb_str);
|
|
+ case ARM64_BP_HARDEN_UNKNOWN:
|
|
+ fallthrough;
|
|
default:
|
|
return sprintf(buf, "Vulnerable\n");
|
|
}
|
|
@@ -1019,3 +1064,333 @@ ssize_t cpu_show_spec_store_bypass(struct device *dev,
|
|
|
|
return sprintf(buf, "Vulnerable\n");
|
|
}
|
|
+
|
|
+/*
|
|
+ * We try to ensure that the mitigation state can never change as the result of
|
|
+ * onlining a late CPU.
|
|
+ */
|
|
+static void update_mitigation_state(enum mitigation_state *oldp,
|
|
+ enum mitigation_state new)
|
|
+{
|
|
+ enum mitigation_state state;
|
|
+
|
|
+ do {
|
|
+ state = READ_ONCE(*oldp);
|
|
+ if (new <= state)
|
|
+ break;
|
|
+ } while (cmpxchg_relaxed(oldp, state, new) != state);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Spectre BHB.
|
|
+ *
|
|
+ * A CPU is either:
|
|
+ * - Mitigated by a branchy loop a CPU specific number of times, and listed
|
|
+ * in our "loop mitigated list".
|
|
+ * - Mitigated in software by the firmware Spectre v2 call.
|
|
+ * - Has the ClearBHB instruction to perform the mitigation.
|
|
+ * - Has the 'Exception Clears Branch History Buffer' (ECBHB) feature, so no
|
|
+ * software mitigation in the vectors is needed.
|
|
+ * - Has CSV2.3, so is unaffected.
|
|
+ */
|
|
+static enum mitigation_state spectre_bhb_state;
|
|
+
|
|
+enum mitigation_state arm64_get_spectre_bhb_state(void)
|
|
+{
|
|
+ return spectre_bhb_state;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * This must be called with SCOPE_LOCAL_CPU for each type of CPU, before any
|
|
+ * SCOPE_SYSTEM call will give the right answer.
|
|
+ */
|
|
+u8 spectre_bhb_loop_affected(int scope)
|
|
+{
|
|
+ u8 k = 0;
|
|
+ static u8 max_bhb_k;
|
|
+
|
|
+ if (scope == SCOPE_LOCAL_CPU) {
|
|
+ static const struct midr_range spectre_bhb_k32_list[] = {
|
|
+ MIDR_ALL_VERSIONS(MIDR_CORTEX_A78),
|
|
+ MIDR_ALL_VERSIONS(MIDR_CORTEX_A78C),
|
|
+ MIDR_ALL_VERSIONS(MIDR_CORTEX_X1),
|
|
+ MIDR_ALL_VERSIONS(MIDR_CORTEX_A710),
|
|
+ MIDR_ALL_VERSIONS(MIDR_CORTEX_X2),
|
|
+ MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N2),
|
|
+ MIDR_ALL_VERSIONS(MIDR_NEOVERSE_V1),
|
|
+ {},
|
|
+ };
|
|
+ static const struct midr_range spectre_bhb_k24_list[] = {
|
|
+ MIDR_ALL_VERSIONS(MIDR_CORTEX_A76),
|
|
+ MIDR_ALL_VERSIONS(MIDR_CORTEX_A77),
|
|
+ MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N1),
|
|
+ {},
|
|
+ };
|
|
+ static const struct midr_range spectre_bhb_k8_list[] = {
|
|
+ MIDR_ALL_VERSIONS(MIDR_CORTEX_A72),
|
|
+ MIDR_ALL_VERSIONS(MIDR_CORTEX_A57),
|
|
+ {},
|
|
+ };
|
|
+
|
|
+ if (is_midr_in_range_list(read_cpuid_id(), spectre_bhb_k32_list))
|
|
+ k = 32;
|
|
+ else if (is_midr_in_range_list(read_cpuid_id(), spectre_bhb_k24_list))
|
|
+ k = 24;
|
|
+ else if (is_midr_in_range_list(read_cpuid_id(), spectre_bhb_k8_list))
|
|
+ k = 8;
|
|
+
|
|
+ max_bhb_k = max(max_bhb_k, k);
|
|
+ } else {
|
|
+ k = max_bhb_k;
|
|
+ }
|
|
+
|
|
+ return k;
|
|
+}
|
|
+
|
|
+static enum mitigation_state spectre_bhb_get_cpu_fw_mitigation_state(void)
|
|
+{
|
|
+ int ret;
|
|
+ struct arm_smccc_res res;
|
|
+
|
|
+ if (psci_ops.smccc_version == SMCCC_VERSION_1_0)
|
|
+ return SPECTRE_VULNERABLE;
|
|
+
|
|
+ switch (psci_ops.conduit) {
|
|
+ case PSCI_CONDUIT_HVC:
|
|
+ arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
|
|
+ ARM_SMCCC_ARCH_WORKAROUND_3, &res);
|
|
+ break;
|
|
+
|
|
+ case PSCI_CONDUIT_SMC:
|
|
+ arm_smccc_1_1_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
|
|
+ ARM_SMCCC_ARCH_WORKAROUND_3, &res);
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ return SPECTRE_VULNERABLE;
|
|
+ }
|
|
+
|
|
+ ret = res.a0;
|
|
+ switch (ret) {
|
|
+ case SMCCC_RET_SUCCESS:
|
|
+ return SPECTRE_MITIGATED;
|
|
+ case SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED:
|
|
+ return SPECTRE_UNAFFECTED;
|
|
+ default:
|
|
+ fallthrough;
|
|
+ case SMCCC_RET_NOT_SUPPORTED:
|
|
+ return SPECTRE_VULNERABLE;
|
|
+ }
|
|
+}
|
|
+
|
|
+static bool is_spectre_bhb_fw_affected(int scope)
|
|
+{
|
|
+ static bool system_affected;
|
|
+ enum mitigation_state fw_state;
|
|
+ bool has_smccc = (psci_ops.smccc_version >= SMCCC_VERSION_1_1);
|
|
+ static const struct midr_range spectre_bhb_firmware_mitigated_list[] = {
|
|
+ MIDR_ALL_VERSIONS(MIDR_CORTEX_A73),
|
|
+ MIDR_ALL_VERSIONS(MIDR_CORTEX_A75),
|
|
+ {},
|
|
+ };
|
|
+ bool cpu_in_list = is_midr_in_range_list(read_cpuid_id(),
|
|
+ spectre_bhb_firmware_mitigated_list);
|
|
+
|
|
+ if (scope != SCOPE_LOCAL_CPU)
|
|
+ return system_affected;
|
|
+
|
|
+ fw_state = spectre_bhb_get_cpu_fw_mitigation_state();
|
|
+ if (cpu_in_list || (has_smccc && fw_state == SPECTRE_MITIGATED)) {
|
|
+ system_affected = true;
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ return false;
|
|
+}
|
|
+
|
|
+static bool supports_ecbhb(int scope)
|
|
+{
|
|
+ u64 mmfr1;
|
|
+
|
|
+ if (scope == SCOPE_LOCAL_CPU)
|
|
+ mmfr1 = read_sysreg_s(SYS_ID_AA64MMFR1_EL1);
|
|
+ else
|
|
+ mmfr1 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR1_EL1);
|
|
+
|
|
+ return cpuid_feature_extract_unsigned_field(mmfr1,
|
|
+ ID_AA64MMFR1_ECBHB_SHIFT);
|
|
+}
|
|
+
|
|
+bool is_spectre_bhb_affected(const struct arm64_cpu_capabilities *entry,
|
|
+ int scope)
|
|
+{
|
|
+ WARN_ON(scope != SCOPE_LOCAL_CPU || preemptible());
|
|
+
|
|
+ if (supports_csv2p3(scope))
|
|
+ return false;
|
|
+
|
|
+ if (supports_clearbhb(scope))
|
|
+ return true;
|
|
+
|
|
+ if (spectre_bhb_loop_affected(scope))
|
|
+ return true;
|
|
+
|
|
+ if (is_spectre_bhb_fw_affected(scope))
|
|
+ return true;
|
|
+
|
|
+ return false;
|
|
+}
|
|
+
|
|
+static void this_cpu_set_vectors(enum arm64_bp_harden_el1_vectors slot)
|
|
+{
|
|
+ const char *v = arm64_get_bp_hardening_vector(slot);
|
|
+
|
|
+ if (slot < 0)
|
|
+ return;
|
|
+
|
|
+ __this_cpu_write(this_cpu_vector, v);
|
|
+
|
|
+ /*
|
|
+ * When KPTI is in use, the vectors are switched when exiting to
|
|
+ * user-space.
|
|
+ */
|
|
+ if (arm64_kernel_unmapped_at_el0())
|
|
+ return;
|
|
+
|
|
+ write_sysreg(v, vbar_el1);
|
|
+ isb();
|
|
+}
|
|
+
|
|
+#ifdef CONFIG_KVM_INDIRECT_VECTORS
|
|
+static const char *kvm_bhb_get_vecs_end(const char *start)
|
|
+{
|
|
+ if (start == __smccc_workaround_3_smc_start)
|
|
+ return __smccc_workaround_3_smc_end;
|
|
+ else if (start == __spectre_bhb_loop_k8_start)
|
|
+ return __spectre_bhb_loop_k8_end;
|
|
+ else if (start == __spectre_bhb_loop_k24_start)
|
|
+ return __spectre_bhb_loop_k24_end;
|
|
+ else if (start == __spectre_bhb_loop_k32_start)
|
|
+ return __spectre_bhb_loop_k32_end;
|
|
+ else if (start == __spectre_bhb_clearbhb_start)
|
|
+ return __spectre_bhb_clearbhb_end;
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static void kvm_setup_bhb_slot(const char *hyp_vecs_start)
|
|
+{
|
|
+ int cpu, slot = -1;
|
|
+ const char *hyp_vecs_end;
|
|
+
|
|
+ if (!IS_ENABLED(CONFIG_KVM) || !is_hyp_mode_available())
|
|
+ return;
|
|
+
|
|
+ hyp_vecs_end = kvm_bhb_get_vecs_end(hyp_vecs_start);
|
|
+ if (WARN_ON_ONCE(!hyp_vecs_start || !hyp_vecs_end))
|
|
+ return;
|
|
+
|
|
+ raw_spin_lock(&bp_lock);
|
|
+ for_each_possible_cpu(cpu) {
|
|
+ if (per_cpu(bp_hardening_data.template_start, cpu) == hyp_vecs_start) {
|
|
+ slot = per_cpu(bp_hardening_data.hyp_vectors_slot, cpu);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (slot == -1) {
|
|
+ slot = atomic_inc_return(&arm64_el2_vector_last_slot);
|
|
+ BUG_ON(slot >= BP_HARDEN_EL2_SLOTS);
|
|
+ __copy_hyp_vect_bpi(slot, hyp_vecs_start, hyp_vecs_end);
|
|
+ }
|
|
+
|
|
+ __this_cpu_write(bp_hardening_data.hyp_vectors_slot, slot);
|
|
+ __this_cpu_write(bp_hardening_data.template_start, hyp_vecs_start);
|
|
+ raw_spin_unlock(&bp_lock);
|
|
+}
|
|
+#else
|
|
+#define __smccc_workaround_3_smc_start NULL
|
|
+#define __spectre_bhb_loop_k8_start NULL
|
|
+#define __spectre_bhb_loop_k24_start NULL
|
|
+#define __spectre_bhb_loop_k32_start NULL
|
|
+#define __spectre_bhb_clearbhb_start NULL
|
|
+
|
|
+static void kvm_setup_bhb_slot(const char *hyp_vecs_start) { }
|
|
+#endif
|
|
+
|
|
+void spectre_bhb_enable_mitigation(const struct arm64_cpu_capabilities *entry)
|
|
+{
|
|
+ enum mitigation_state fw_state, state = SPECTRE_VULNERABLE;
|
|
+
|
|
+ if (!is_spectre_bhb_affected(entry, SCOPE_LOCAL_CPU))
|
|
+ return;
|
|
+
|
|
+ if (get_spectre_v2_workaround_state() == ARM64_BP_HARDEN_UNKNOWN) {
|
|
+ /* No point mitigating Spectre-BHB alone. */
|
|
+ } else if (!IS_ENABLED(CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY)) {
|
|
+ pr_info_once("spectre-bhb mitigation disabled by compile time option\n");
|
|
+ } else if (cpu_mitigations_off()) {
|
|
+ pr_info_once("spectre-bhb mitigation disabled by command line option\n");
|
|
+ } else if (supports_ecbhb(SCOPE_LOCAL_CPU)) {
|
|
+ state = SPECTRE_MITIGATED;
|
|
+ } else if (supports_clearbhb(SCOPE_LOCAL_CPU)) {
|
|
+ kvm_setup_bhb_slot(__spectre_bhb_clearbhb_start);
|
|
+ this_cpu_set_vectors(EL1_VECTOR_BHB_CLEAR_INSN);
|
|
+
|
|
+ state = SPECTRE_MITIGATED;
|
|
+ } else if (spectre_bhb_loop_affected(SCOPE_LOCAL_CPU)) {
|
|
+ switch (spectre_bhb_loop_affected(SCOPE_SYSTEM)) {
|
|
+ case 8:
|
|
+ kvm_setup_bhb_slot(__spectre_bhb_loop_k8_start);
|
|
+ break;
|
|
+ case 24:
|
|
+ kvm_setup_bhb_slot(__spectre_bhb_loop_k24_start);
|
|
+ break;
|
|
+ case 32:
|
|
+ kvm_setup_bhb_slot(__spectre_bhb_loop_k32_start);
|
|
+ break;
|
|
+ default:
|
|
+ WARN_ON_ONCE(1);
|
|
+ }
|
|
+ this_cpu_set_vectors(EL1_VECTOR_BHB_LOOP);
|
|
+
|
|
+ state = SPECTRE_MITIGATED;
|
|
+ } else if (is_spectre_bhb_fw_affected(SCOPE_LOCAL_CPU)) {
|
|
+ fw_state = spectre_bhb_get_cpu_fw_mitigation_state();
|
|
+ if (fw_state == SPECTRE_MITIGATED) {
|
|
+ kvm_setup_bhb_slot(__smccc_workaround_3_smc_start);
|
|
+ this_cpu_set_vectors(EL1_VECTOR_BHB_FW);
|
|
+
|
|
+ /*
|
|
+ * With WA3 in the vectors, the WA1 calls can be
|
|
+ * removed.
|
|
+ */
|
|
+ __this_cpu_write(bp_hardening_data.fn, NULL);
|
|
+
|
|
+ state = SPECTRE_MITIGATED;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ update_mitigation_state(&spectre_bhb_state, state);
|
|
+}
|
|
+
|
|
+/* Patched to correct the immediate */
|
|
+void noinstr spectre_bhb_patch_loop_iter(struct alt_instr *alt,
|
|
+ __le32 *origptr, __le32 *updptr, int nr_inst)
|
|
+{
|
|
+ u8 rd;
|
|
+ u32 insn;
|
|
+ u16 loop_count = spectre_bhb_loop_affected(SCOPE_SYSTEM);
|
|
+
|
|
+ BUG_ON(nr_inst != 1); /* MOV -> MOV */
|
|
+
|
|
+ if (!IS_ENABLED(CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY))
|
|
+ return;
|
|
+
|
|
+ insn = le32_to_cpu(*origptr);
|
|
+ rd = aarch64_insn_decode_register(AARCH64_INSN_REGTYPE_RD, insn);
|
|
+ insn = aarch64_insn_gen_movewide(rd, loop_count, 0,
|
|
+ AARCH64_INSN_VARIANT_64BIT,
|
|
+ AARCH64_INSN_MOVEWIDE_ZERO);
|
|
+ *updptr++ = cpu_to_le32(insn);
|
|
+}
|
|
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
|
|
index acdef8d76c64d..d07dadd6b8ff7 100644
|
|
--- a/arch/arm64/kernel/cpufeature.c
|
|
+++ b/arch/arm64/kernel/cpufeature.c
|
|
@@ -10,11 +10,13 @@
|
|
#include <linux/bsearch.h>
|
|
#include <linux/cpumask.h>
|
|
#include <linux/crash_dump.h>
|
|
+#include <linux/percpu.h>
|
|
#include <linux/sort.h>
|
|
#include <linux/stop_machine.h>
|
|
#include <linux/types.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/cpu.h>
|
|
+
|
|
#include <asm/cpu.h>
|
|
#include <asm/cpufeature.h>
|
|
#include <asm/cpu_ops.h>
|
|
@@ -23,6 +25,7 @@
|
|
#include <asm/processor.h>
|
|
#include <asm/sysreg.h>
|
|
#include <asm/traps.h>
|
|
+#include <asm/vectors.h>
|
|
#include <asm/virt.h>
|
|
|
|
/* Kernel representation of AT_HWCAP and AT_HWCAP2 */
|
|
@@ -45,6 +48,8 @@ static struct arm64_cpu_capabilities const __ro_after_init *cpu_hwcaps_ptrs[ARM6
|
|
/* Need also bit for ARM64_CB_PATCH */
|
|
DECLARE_BITMAP(boot_capabilities, ARM64_NPATCHABLE);
|
|
|
|
+DEFINE_PER_CPU_READ_MOSTLY(const char *, this_cpu_vector) = vectors;
|
|
+
|
|
/*
|
|
* Flag to indicate if we have computed the system wide
|
|
* capabilities based on the boot time active CPUs. This
|
|
@@ -150,6 +155,11 @@ static const struct arm64_ftr_bits ftr_id_aa64isar1[] = {
|
|
ARM64_FTR_END,
|
|
};
|
|
|
|
+static const struct arm64_ftr_bits ftr_id_aa64isar2[] = {
|
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_HIGHER_SAFE, ID_AA64ISAR2_CLEARBHB_SHIFT, 4, 0),
|
|
+ ARM64_FTR_END,
|
|
+};
|
|
+
|
|
static const struct arm64_ftr_bits ftr_id_aa64pfr0[] = {
|
|
ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_CSV3_SHIFT, 4, 0),
|
|
ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_CSV2_SHIFT, 4, 0),
|
|
@@ -410,6 +420,7 @@ static const struct __ftr_reg_entry {
|
|
/* Op1 = 0, CRn = 0, CRm = 6 */
|
|
ARM64_FTR_REG(SYS_ID_AA64ISAR0_EL1, ftr_id_aa64isar0),
|
|
ARM64_FTR_REG(SYS_ID_AA64ISAR1_EL1, ftr_id_aa64isar1),
|
|
+ ARM64_FTR_REG(SYS_ID_AA64ISAR2_EL1, ftr_id_aa64isar2),
|
|
|
|
/* Op1 = 0, CRn = 0, CRm = 7 */
|
|
ARM64_FTR_REG(SYS_ID_AA64MMFR0_EL1, ftr_id_aa64mmfr0),
|
|
@@ -581,6 +592,7 @@ void __init init_cpu_features(struct cpuinfo_arm64 *info)
|
|
init_cpu_ftr_reg(SYS_ID_AA64DFR1_EL1, info->reg_id_aa64dfr1);
|
|
init_cpu_ftr_reg(SYS_ID_AA64ISAR0_EL1, info->reg_id_aa64isar0);
|
|
init_cpu_ftr_reg(SYS_ID_AA64ISAR1_EL1, info->reg_id_aa64isar1);
|
|
+ init_cpu_ftr_reg(SYS_ID_AA64ISAR2_EL1, info->reg_id_aa64isar2);
|
|
init_cpu_ftr_reg(SYS_ID_AA64MMFR0_EL1, info->reg_id_aa64mmfr0);
|
|
init_cpu_ftr_reg(SYS_ID_AA64MMFR1_EL1, info->reg_id_aa64mmfr1);
|
|
init_cpu_ftr_reg(SYS_ID_AA64MMFR2_EL1, info->reg_id_aa64mmfr2);
|
|
@@ -704,6 +716,8 @@ void update_cpu_features(int cpu,
|
|
info->reg_id_aa64isar0, boot->reg_id_aa64isar0);
|
|
taint |= check_update_ftr_reg(SYS_ID_AA64ISAR1_EL1, cpu,
|
|
info->reg_id_aa64isar1, boot->reg_id_aa64isar1);
|
|
+ taint |= check_update_ftr_reg(SYS_ID_AA64ISAR2_EL1, cpu,
|
|
+ info->reg_id_aa64isar2, boot->reg_id_aa64isar2);
|
|
|
|
/*
|
|
* Differing PARange support is fine as long as all peripherals and
|
|
@@ -838,6 +852,7 @@ static u64 __read_sysreg_by_encoding(u32 sys_id)
|
|
read_sysreg_case(SYS_ID_AA64MMFR2_EL1);
|
|
read_sysreg_case(SYS_ID_AA64ISAR0_EL1);
|
|
read_sysreg_case(SYS_ID_AA64ISAR1_EL1);
|
|
+ read_sysreg_case(SYS_ID_AA64ISAR2_EL1);
|
|
|
|
read_sysreg_case(SYS_CNTFRQ_EL0);
|
|
read_sysreg_case(SYS_CTR_EL0);
|
|
@@ -1038,6 +1053,12 @@ kpti_install_ng_mappings(const struct arm64_cpu_capabilities *__unused)
|
|
static bool kpti_applied = false;
|
|
int cpu = smp_processor_id();
|
|
|
|
+ if (__this_cpu_read(this_cpu_vector) == vectors) {
|
|
+ const char *v = arm64_get_bp_hardening_vector(EL1_VECTOR_KPTI);
|
|
+
|
|
+ __this_cpu_write(this_cpu_vector, v);
|
|
+ }
|
|
+
|
|
/*
|
|
* We don't need to rewrite the page-tables if either we've done
|
|
* it already or we have KASLR enabled and therefore have not
|
|
diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c
|
|
index 05933c065732b..90b35011a22f8 100644
|
|
--- a/arch/arm64/kernel/cpuinfo.c
|
|
+++ b/arch/arm64/kernel/cpuinfo.c
|
|
@@ -344,6 +344,7 @@ static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info)
|
|
info->reg_id_aa64dfr1 = read_cpuid(ID_AA64DFR1_EL1);
|
|
info->reg_id_aa64isar0 = read_cpuid(ID_AA64ISAR0_EL1);
|
|
info->reg_id_aa64isar1 = read_cpuid(ID_AA64ISAR1_EL1);
|
|
+ info->reg_id_aa64isar2 = read_cpuid(ID_AA64ISAR2_EL1);
|
|
info->reg_id_aa64mmfr0 = read_cpuid(ID_AA64MMFR0_EL1);
|
|
info->reg_id_aa64mmfr1 = read_cpuid(ID_AA64MMFR1_EL1);
|
|
info->reg_id_aa64mmfr2 = read_cpuid(ID_AA64MMFR2_EL1);
|
|
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
|
|
index db137746c6fa3..8a4c108a0c0b6 100644
|
|
--- a/arch/arm64/kernel/entry.S
|
|
+++ b/arch/arm64/kernel/entry.S
|
|
@@ -59,18 +59,21 @@
|
|
|
|
.macro kernel_ventry, el, label, regsize = 64
|
|
.align 7
|
|
-#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
|
|
-alternative_if ARM64_UNMAP_KERNEL_AT_EL0
|
|
+.Lventry_start\@:
|
|
.if \el == 0
|
|
+ /*
|
|
+ * This must be the first instruction of the EL0 vector entries. It is
|
|
+ * skipped by the trampoline vectors, to trigger the cleanup.
|
|
+ */
|
|
+ b .Lskip_tramp_vectors_cleanup\@
|
|
.if \regsize == 64
|
|
mrs x30, tpidrro_el0
|
|
msr tpidrro_el0, xzr
|
|
.else
|
|
mov x30, xzr
|
|
.endif
|
|
+.Lskip_tramp_vectors_cleanup\@:
|
|
.endif
|
|
-alternative_else_nop_endif
|
|
-#endif
|
|
|
|
sub sp, sp, #S_FRAME_SIZE
|
|
#ifdef CONFIG_VMAP_STACK
|
|
@@ -116,11 +119,15 @@ alternative_else_nop_endif
|
|
mrs x0, tpidrro_el0
|
|
#endif
|
|
b el\()\el\()_\label
|
|
+.org .Lventry_start\@ + 128 // Did we overflow the ventry slot?
|
|
.endm
|
|
|
|
- .macro tramp_alias, dst, sym
|
|
+ .macro tramp_alias, dst, sym, tmp
|
|
mov_q \dst, TRAMP_VALIAS
|
|
- add \dst, \dst, #(\sym - .entry.tramp.text)
|
|
+ adr_l \tmp, \sym
|
|
+ add \dst, \dst, \tmp
|
|
+ adr_l \tmp, .entry.tramp.text
|
|
+ sub \dst, \dst, \tmp
|
|
.endm
|
|
|
|
// This macro corrupts x0-x3. It is the caller's duty
|
|
@@ -361,21 +368,25 @@ alternative_else_nop_endif
|
|
ldp x24, x25, [sp, #16 * 12]
|
|
ldp x26, x27, [sp, #16 * 13]
|
|
ldp x28, x29, [sp, #16 * 14]
|
|
- ldr lr, [sp, #S_LR]
|
|
- add sp, sp, #S_FRAME_SIZE // restore sp
|
|
|
|
.if \el == 0
|
|
-alternative_insn eret, nop, ARM64_UNMAP_KERNEL_AT_EL0
|
|
+alternative_if_not ARM64_UNMAP_KERNEL_AT_EL0
|
|
+ ldr lr, [sp, #S_LR]
|
|
+ add sp, sp, #S_FRAME_SIZE // restore sp
|
|
+ eret
|
|
+alternative_else_nop_endif
|
|
#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
|
|
bne 5f
|
|
- msr far_el1, x30
|
|
- tramp_alias x30, tramp_exit_native
|
|
+ msr far_el1, x29
|
|
+ tramp_alias x30, tramp_exit_native, x29
|
|
br x30
|
|
5:
|
|
- tramp_alias x30, tramp_exit_compat
|
|
+ tramp_alias x30, tramp_exit_compat, x29
|
|
br x30
|
|
#endif
|
|
.else
|
|
+ ldr lr, [sp, #S_LR]
|
|
+ add sp, sp, #S_FRAME_SIZE // restore sp
|
|
eret
|
|
.endif
|
|
sb
|
|
@@ -1012,12 +1023,6 @@ ENDPROC(el0_svc)
|
|
|
|
.popsection // .entry.text
|
|
|
|
-#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
|
|
-/*
|
|
- * Exception vectors trampoline.
|
|
- */
|
|
- .pushsection ".entry.tramp.text", "ax"
|
|
-
|
|
// Move from tramp_pg_dir to swapper_pg_dir
|
|
.macro tramp_map_kernel, tmp
|
|
mrs \tmp, ttbr1_el1
|
|
@@ -1051,12 +1056,47 @@ alternative_else_nop_endif
|
|
*/
|
|
.endm
|
|
|
|
- .macro tramp_ventry, regsize = 64
|
|
+ .macro tramp_data_page dst
|
|
+ adr_l \dst, .entry.tramp.text
|
|
+ sub \dst, \dst, PAGE_SIZE
|
|
+ .endm
|
|
+
|
|
+ .macro tramp_data_read_var dst, var
|
|
+#ifdef CONFIG_RANDOMIZE_BASE
|
|
+ tramp_data_page \dst
|
|
+ add \dst, \dst, #:lo12:__entry_tramp_data_\var
|
|
+ ldr \dst, [\dst]
|
|
+#else
|
|
+ ldr \dst, =\var
|
|
+#endif
|
|
+ .endm
|
|
+
|
|
+#define BHB_MITIGATION_NONE 0
|
|
+#define BHB_MITIGATION_LOOP 1
|
|
+#define BHB_MITIGATION_FW 2
|
|
+#define BHB_MITIGATION_INSN 3
|
|
+
|
|
+ .macro tramp_ventry, vector_start, regsize, kpti, bhb
|
|
.align 7
|
|
1:
|
|
.if \regsize == 64
|
|
msr tpidrro_el0, x30 // Restored in kernel_ventry
|
|
.endif
|
|
+
|
|
+ .if \bhb == BHB_MITIGATION_LOOP
|
|
+ /*
|
|
+ * This sequence must appear before the first indirect branch. i.e. the
|
|
+ * ret out of tramp_ventry. It appears here because x30 is free.
|
|
+ */
|
|
+ __mitigate_spectre_bhb_loop x30
|
|
+ .endif // \bhb == BHB_MITIGATION_LOOP
|
|
+
|
|
+ .if \bhb == BHB_MITIGATION_INSN
|
|
+ clearbhb
|
|
+ isb
|
|
+ .endif // \bhb == BHB_MITIGATION_INSN
|
|
+
|
|
+ .if \kpti == 1
|
|
/*
|
|
* Defend against branch aliasing attacks by pushing a dummy
|
|
* entry onto the return stack and using a RET instruction to
|
|
@@ -1066,46 +1106,79 @@ alternative_else_nop_endif
|
|
b .
|
|
2:
|
|
tramp_map_kernel x30
|
|
-#ifdef CONFIG_RANDOMIZE_BASE
|
|
- adr x30, tramp_vectors + PAGE_SIZE
|
|
alternative_insn isb, nop, ARM64_WORKAROUND_QCOM_FALKOR_E1003
|
|
- ldr x30, [x30]
|
|
-#else
|
|
- ldr x30, =vectors
|
|
-#endif
|
|
+ tramp_data_read_var x30, vectors
|
|
alternative_if_not ARM64_WORKAROUND_CAVIUM_TX2_219_PRFM
|
|
- prfm plil1strm, [x30, #(1b - tramp_vectors)]
|
|
+ prfm plil1strm, [x30, #(1b - \vector_start)]
|
|
alternative_else_nop_endif
|
|
+
|
|
msr vbar_el1, x30
|
|
- add x30, x30, #(1b - tramp_vectors)
|
|
isb
|
|
+ .else
|
|
+ ldr x30, =vectors
|
|
+ .endif // \kpti == 1
|
|
+
|
|
+ .if \bhb == BHB_MITIGATION_FW
|
|
+ /*
|
|
+ * The firmware sequence must appear before the first indirect branch.
|
|
+ * i.e. the ret out of tramp_ventry. But it also needs the stack to be
|
|
+ * mapped to save/restore the registers the SMC clobbers.
|
|
+ */
|
|
+ __mitigate_spectre_bhb_fw
|
|
+ .endif // \bhb == BHB_MITIGATION_FW
|
|
+
|
|
+ add x30, x30, #(1b - \vector_start + 4)
|
|
ret
|
|
+.org 1b + 128 // Did we overflow the ventry slot?
|
|
.endm
|
|
|
|
.macro tramp_exit, regsize = 64
|
|
- adr x30, tramp_vectors
|
|
+ tramp_data_read_var x30, this_cpu_vector
|
|
+alternative_if_not ARM64_HAS_VIRT_HOST_EXTN
|
|
+ mrs x29, tpidr_el1
|
|
+alternative_else
|
|
+ mrs x29, tpidr_el2
|
|
+alternative_endif
|
|
+ ldr x30, [x30, x29]
|
|
+
|
|
msr vbar_el1, x30
|
|
- tramp_unmap_kernel x30
|
|
+ ldr lr, [sp, #S_LR]
|
|
+ tramp_unmap_kernel x29
|
|
.if \regsize == 64
|
|
- mrs x30, far_el1
|
|
+ mrs x29, far_el1
|
|
.endif
|
|
+ add sp, sp, #S_FRAME_SIZE // restore sp
|
|
eret
|
|
sb
|
|
.endm
|
|
|
|
- .align 11
|
|
-ENTRY(tramp_vectors)
|
|
+ .macro generate_tramp_vector, kpti, bhb
|
|
+.Lvector_start\@:
|
|
.space 0x400
|
|
|
|
- tramp_ventry
|
|
- tramp_ventry
|
|
- tramp_ventry
|
|
- tramp_ventry
|
|
+ .rept 4
|
|
+ tramp_ventry .Lvector_start\@, 64, \kpti, \bhb
|
|
+ .endr
|
|
+ .rept 4
|
|
+ tramp_ventry .Lvector_start\@, 32, \kpti, \bhb
|
|
+ .endr
|
|
+ .endm
|
|
|
|
- tramp_ventry 32
|
|
- tramp_ventry 32
|
|
- tramp_ventry 32
|
|
- tramp_ventry 32
|
|
+#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
|
|
+/*
|
|
+ * Exception vectors trampoline.
|
|
+ * The order must match __bp_harden_el1_vectors and the
|
|
+ * arm64_bp_harden_el1_vectors enum.
|
|
+ */
|
|
+ .pushsection ".entry.tramp.text", "ax"
|
|
+ .align 11
|
|
+ENTRY(tramp_vectors)
|
|
+#ifdef CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY
|
|
+ generate_tramp_vector kpti=1, bhb=BHB_MITIGATION_LOOP
|
|
+ generate_tramp_vector kpti=1, bhb=BHB_MITIGATION_FW
|
|
+ generate_tramp_vector kpti=1, bhb=BHB_MITIGATION_INSN
|
|
+#endif /* CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY */
|
|
+ generate_tramp_vector kpti=1, bhb=BHB_MITIGATION_NONE
|
|
END(tramp_vectors)
|
|
|
|
ENTRY(tramp_exit_native)
|
|
@@ -1123,11 +1196,55 @@ END(tramp_exit_compat)
|
|
.align PAGE_SHIFT
|
|
.globl __entry_tramp_data_start
|
|
__entry_tramp_data_start:
|
|
+__entry_tramp_data_vectors:
|
|
.quad vectors
|
|
+#ifdef CONFIG_ARM_SDE_INTERFACE
|
|
+__entry_tramp_data___sdei_asm_handler:
|
|
+ .quad __sdei_asm_handler
|
|
+#endif /* CONFIG_ARM_SDE_INTERFACE */
|
|
+__entry_tramp_data_this_cpu_vector:
|
|
+ .quad this_cpu_vector
|
|
.popsection // .rodata
|
|
#endif /* CONFIG_RANDOMIZE_BASE */
|
|
#endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */
|
|
|
|
+/*
|
|
+ * Exception vectors for spectre mitigations on entry from EL1 when
|
|
+ * kpti is not in use.
|
|
+ */
|
|
+ .macro generate_el1_vector, bhb
|
|
+.Lvector_start\@:
|
|
+ kernel_ventry 1, sync_invalid // Synchronous EL1t
|
|
+ kernel_ventry 1, irq_invalid // IRQ EL1t
|
|
+ kernel_ventry 1, fiq_invalid // FIQ EL1t
|
|
+ kernel_ventry 1, error_invalid // Error EL1t
|
|
+
|
|
+ kernel_ventry 1, sync // Synchronous EL1h
|
|
+ kernel_ventry 1, irq // IRQ EL1h
|
|
+ kernel_ventry 1, fiq_invalid // FIQ EL1h
|
|
+ kernel_ventry 1, error // Error EL1h
|
|
+
|
|
+ .rept 4
|
|
+ tramp_ventry .Lvector_start\@, 64, 0, \bhb
|
|
+ .endr
|
|
+ .rept 4
|
|
+ tramp_ventry .Lvector_start\@, 32, 0, \bhb
|
|
+ .endr
|
|
+ .endm
|
|
+
|
|
+/* The order must match tramp_vecs and the arm64_bp_harden_el1_vectors enum. */
|
|
+ .pushsection ".entry.text", "ax"
|
|
+ .align 11
|
|
+SYM_CODE_START(__bp_harden_el1_vectors)
|
|
+#ifdef CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY
|
|
+ generate_el1_vector bhb=BHB_MITIGATION_LOOP
|
|
+ generate_el1_vector bhb=BHB_MITIGATION_FW
|
|
+ generate_el1_vector bhb=BHB_MITIGATION_INSN
|
|
+#endif /* CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY */
|
|
+SYM_CODE_END(__bp_harden_el1_vectors)
|
|
+ .popsection
|
|
+
|
|
+
|
|
/*
|
|
* Register switch for AArch64. The callee-saved registers need to be saved
|
|
* and restored. On entry:
|
|
@@ -1214,13 +1331,7 @@ ENTRY(__sdei_asm_entry_trampoline)
|
|
*/
|
|
1: str x4, [x1, #(SDEI_EVENT_INTREGS + S_ORIG_ADDR_LIMIT)]
|
|
|
|
-#ifdef CONFIG_RANDOMIZE_BASE
|
|
- adr x4, tramp_vectors + PAGE_SIZE
|
|
- add x4, x4, #:lo12:__sdei_asm_trampoline_next_handler
|
|
- ldr x4, [x4]
|
|
-#else
|
|
- ldr x4, =__sdei_asm_handler
|
|
-#endif
|
|
+ tramp_data_read_var x4, __sdei_asm_handler
|
|
br x4
|
|
ENDPROC(__sdei_asm_entry_trampoline)
|
|
NOKPROBE(__sdei_asm_entry_trampoline)
|
|
@@ -1243,12 +1354,6 @@ ENDPROC(__sdei_asm_exit_trampoline)
|
|
NOKPROBE(__sdei_asm_exit_trampoline)
|
|
.ltorg
|
|
.popsection // .entry.tramp.text
|
|
-#ifdef CONFIG_RANDOMIZE_BASE
|
|
-.pushsection ".rodata", "a"
|
|
-__sdei_asm_trampoline_next_handler:
|
|
- .quad __sdei_asm_handler
|
|
-.popsection // .rodata
|
|
-#endif /* CONFIG_RANDOMIZE_BASE */
|
|
#endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */
|
|
|
|
/*
|
|
@@ -1344,7 +1449,7 @@ alternative_if_not ARM64_UNMAP_KERNEL_AT_EL0
|
|
alternative_else_nop_endif
|
|
|
|
#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
|
|
- tramp_alias dst=x5, sym=__sdei_asm_exit_trampoline
|
|
+ tramp_alias dst=x5, sym=__sdei_asm_exit_trampoline, tmp=x3
|
|
br x5
|
|
#endif
|
|
ENDPROC(__sdei_asm_handler)
|
|
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
|
|
index 1f82cf631c3c4..fbab044b3a39a 100644
|
|
--- a/arch/arm64/kernel/vmlinux.lds.S
|
|
+++ b/arch/arm64/kernel/vmlinux.lds.S
|
|
@@ -276,7 +276,7 @@ ASSERT(__hibernate_exit_text_end - (__hibernate_exit_text_start & ~(SZ_4K - 1))
|
|
<= SZ_4K, "Hibernate exit text too big or misaligned")
|
|
#endif
|
|
#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
|
|
-ASSERT((__entry_tramp_text_end - __entry_tramp_text_start) == PAGE_SIZE,
|
|
+ASSERT((__entry_tramp_text_end - __entry_tramp_text_start) <= 3*PAGE_SIZE,
|
|
"Entry trampoline text too big")
|
|
#endif
|
|
/*
|
|
diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S
|
|
index f36aad0f207bb..99b8ecaae8109 100644
|
|
--- a/arch/arm64/kvm/hyp/hyp-entry.S
|
|
+++ b/arch/arm64/kvm/hyp/hyp-entry.S
|
|
@@ -113,6 +113,10 @@ el1_hvc_guest:
|
|
/* ARM_SMCCC_ARCH_WORKAROUND_2 handling */
|
|
eor w1, w1, #(ARM_SMCCC_ARCH_WORKAROUND_1 ^ \
|
|
ARM_SMCCC_ARCH_WORKAROUND_2)
|
|
+ cbz w1, wa_epilogue
|
|
+
|
|
+ eor w1, w1, #(ARM_SMCCC_ARCH_WORKAROUND_2 ^ \
|
|
+ ARM_SMCCC_ARCH_WORKAROUND_3)
|
|
cbnz w1, el1_trap
|
|
|
|
#ifdef CONFIG_ARM64_SSBD
|
|
@@ -347,4 +351,64 @@ ENTRY(__smccc_workaround_1_smc_start)
|
|
ldp x0, x1, [sp, #(8 * 2)]
|
|
add sp, sp, #(8 * 4)
|
|
ENTRY(__smccc_workaround_1_smc_end)
|
|
+
|
|
+ENTRY(__smccc_workaround_3_smc_start)
|
|
+ esb
|
|
+ sub sp, sp, #(8 * 4)
|
|
+ stp x2, x3, [sp, #(8 * 0)]
|
|
+ stp x0, x1, [sp, #(8 * 2)]
|
|
+ mov w0, #ARM_SMCCC_ARCH_WORKAROUND_3
|
|
+ smc #0
|
|
+ ldp x2, x3, [sp, #(8 * 0)]
|
|
+ ldp x0, x1, [sp, #(8 * 2)]
|
|
+ add sp, sp, #(8 * 4)
|
|
+ENTRY(__smccc_workaround_3_smc_end)
|
|
+
|
|
+ENTRY(__spectre_bhb_loop_k8_start)
|
|
+ esb
|
|
+ sub sp, sp, #(8 * 2)
|
|
+ stp x0, x1, [sp, #(8 * 0)]
|
|
+ mov x0, #8
|
|
+2: b . + 4
|
|
+ subs x0, x0, #1
|
|
+ b.ne 2b
|
|
+ dsb nsh
|
|
+ isb
|
|
+ ldp x0, x1, [sp, #(8 * 0)]
|
|
+ add sp, sp, #(8 * 2)
|
|
+ENTRY(__spectre_bhb_loop_k8_end)
|
|
+
|
|
+ENTRY(__spectre_bhb_loop_k24_start)
|
|
+ esb
|
|
+ sub sp, sp, #(8 * 2)
|
|
+ stp x0, x1, [sp, #(8 * 0)]
|
|
+ mov x0, #24
|
|
+2: b . + 4
|
|
+ subs x0, x0, #1
|
|
+ b.ne 2b
|
|
+ dsb nsh
|
|
+ isb
|
|
+ ldp x0, x1, [sp, #(8 * 0)]
|
|
+ add sp, sp, #(8 * 2)
|
|
+ENTRY(__spectre_bhb_loop_k24_end)
|
|
+
|
|
+ENTRY(__spectre_bhb_loop_k32_start)
|
|
+ esb
|
|
+ sub sp, sp, #(8 * 2)
|
|
+ stp x0, x1, [sp, #(8 * 0)]
|
|
+ mov x0, #32
|
|
+2: b . + 4
|
|
+ subs x0, x0, #1
|
|
+ b.ne 2b
|
|
+ dsb nsh
|
|
+ isb
|
|
+ ldp x0, x1, [sp, #(8 * 0)]
|
|
+ add sp, sp, #(8 * 2)
|
|
+ENTRY(__spectre_bhb_loop_k32_end)
|
|
+
|
|
+ENTRY(__spectre_bhb_clearbhb_start)
|
|
+ esb
|
|
+ clearbhb
|
|
+ isb
|
|
+ENTRY(__spectre_bhb_clearbhb_end)
|
|
#endif
|
|
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
|
|
index 14607fac7ca38..768983bd23261 100644
|
|
--- a/arch/arm64/kvm/hyp/switch.c
|
|
+++ b/arch/arm64/kvm/hyp/switch.c
|
|
@@ -25,6 +25,7 @@
|
|
#include <asm/debug-monitors.h>
|
|
#include <asm/processor.h>
|
|
#include <asm/thread_info.h>
|
|
+#include <asm/vectors.h>
|
|
|
|
extern struct exception_table_entry __start___kvm_ex_table;
|
|
extern struct exception_table_entry __stop___kvm_ex_table;
|
|
@@ -152,7 +153,7 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
|
|
|
|
static void deactivate_traps_vhe(void)
|
|
{
|
|
- extern char vectors[]; /* kernel exception vectors */
|
|
+ const char *host_vectors = vectors;
|
|
write_sysreg(HCR_HOST_VHE_FLAGS, hcr_el2);
|
|
|
|
/*
|
|
@@ -163,7 +164,10 @@ static void deactivate_traps_vhe(void)
|
|
asm(ALTERNATIVE("nop", "isb", ARM64_WORKAROUND_1165522));
|
|
|
|
write_sysreg(CPACR_EL1_DEFAULT, cpacr_el1);
|
|
- write_sysreg(vectors, vbar_el1);
|
|
+
|
|
+ if (!arm64_kernel_unmapped_at_el0())
|
|
+ host_vectors = __this_cpu_read(this_cpu_vector);
|
|
+ write_sysreg(host_vectors, vbar_el1);
|
|
}
|
|
NOKPROBE_SYMBOL(deactivate_traps_vhe);
|
|
|
|
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
|
|
index da649e90240c8..a25f737dfa0bb 100644
|
|
--- a/arch/arm64/kvm/sys_regs.c
|
|
+++ b/arch/arm64/kvm/sys_regs.c
|
|
@@ -1454,7 +1454,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
|
|
/* CRm=6 */
|
|
ID_SANITISED(ID_AA64ISAR0_EL1),
|
|
ID_SANITISED(ID_AA64ISAR1_EL1),
|
|
- ID_UNALLOCATED(6,2),
|
|
+ ID_SANITISED(ID_AA64ISAR2_EL1),
|
|
ID_UNALLOCATED(6,3),
|
|
ID_UNALLOCATED(6,4),
|
|
ID_UNALLOCATED(6,5),
|
|
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
|
|
index 99bc0289ab2b6..5cf575f23af28 100644
|
|
--- a/arch/arm64/mm/mmu.c
|
|
+++ b/arch/arm64/mm/mmu.c
|
|
@@ -583,6 +583,8 @@ early_param("rodata", parse_rodata);
|
|
#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
|
|
static int __init map_entry_trampoline(void)
|
|
{
|
|
+ int i;
|
|
+
|
|
pgprot_t prot = rodata_enabled ? PAGE_KERNEL_ROX : PAGE_KERNEL_EXEC;
|
|
phys_addr_t pa_start = __pa_symbol(__entry_tramp_text_start);
|
|
|
|
@@ -591,11 +593,15 @@ static int __init map_entry_trampoline(void)
|
|
|
|
/* Map only the text into the trampoline page table */
|
|
memset(tramp_pg_dir, 0, PGD_SIZE);
|
|
- __create_pgd_mapping(tramp_pg_dir, pa_start, TRAMP_VALIAS, PAGE_SIZE,
|
|
- prot, __pgd_pgtable_alloc, 0);
|
|
+ __create_pgd_mapping(tramp_pg_dir, pa_start, TRAMP_VALIAS,
|
|
+ entry_tramp_text_size(), prot,
|
|
+ __pgd_pgtable_alloc, NO_BLOCK_MAPPINGS);
|
|
|
|
/* Map both the text and data into the kernel page table */
|
|
- __set_fixmap(FIX_ENTRY_TRAMP_TEXT, pa_start, prot);
|
|
+ for (i = 0; i < DIV_ROUND_UP(entry_tramp_text_size(), PAGE_SIZE); i++)
|
|
+ __set_fixmap(FIX_ENTRY_TRAMP_TEXT1 - i,
|
|
+ pa_start + i * PAGE_SIZE, prot);
|
|
+
|
|
if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
|
|
extern char __entry_tramp_data_start[];
|
|
|
|
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
|
|
index f510c00bda882..c563b03bdccc1 100644
|
|
--- a/arch/mips/kernel/smp.c
|
|
+++ b/arch/mips/kernel/smp.c
|
|
@@ -361,6 +361,9 @@ asmlinkage void start_secondary(void)
|
|
cpu = smp_processor_id();
|
|
cpu_data[cpu].udelay_val = loops_per_jiffy;
|
|
|
|
+ set_cpu_sibling_map(cpu);
|
|
+ set_cpu_core_map(cpu);
|
|
+
|
|
cpumask_set_cpu(cpu, &cpu_coherent_mask);
|
|
notify_cpu_starting(cpu);
|
|
|
|
@@ -372,9 +375,6 @@ asmlinkage void start_secondary(void)
|
|
/* The CPU is running and counters synchronised, now mark it online */
|
|
set_cpu_online(cpu, true);
|
|
|
|
- set_cpu_sibling_map(cpu);
|
|
- set_cpu_core_map(cpu);
|
|
-
|
|
calculate_cpu_foreign_map();
|
|
|
|
/*
|
|
diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c
|
|
index 5acb459856752..8995c39330fac 100644
|
|
--- a/drivers/atm/firestream.c
|
|
+++ b/drivers/atm/firestream.c
|
|
@@ -1677,6 +1677,8 @@ static int fs_init(struct fs_dev *dev)
|
|
dev->hw_base = pci_resource_start(pci_dev, 0);
|
|
|
|
dev->base = ioremap(dev->hw_base, 0x1000);
|
|
+ if (!dev->base)
|
|
+ return 1;
|
|
|
|
reset_chip (dev);
|
|
|
|
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
|
|
index 2337b3827e6a4..11a81e8ba9639 100644
|
|
--- a/drivers/gpu/drm/drm_connector.c
|
|
+++ b/drivers/gpu/drm/drm_connector.c
|
|
@@ -1984,6 +1984,9 @@ EXPORT_SYMBOL(drm_connector_attach_max_bpc_property);
|
|
void drm_connector_set_vrr_capable_property(
|
|
struct drm_connector *connector, bool capable)
|
|
{
|
|
+ if (!connector->vrr_capable_property)
|
|
+ return;
|
|
+
|
|
drm_object_property_set_value(&connector->base,
|
|
connector->vrr_capable_property,
|
|
capable);
|
|
diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c
|
|
index edaa1ca972c15..d4e9815ca26ff 100644
|
|
--- a/drivers/net/can/rcar/rcar_canfd.c
|
|
+++ b/drivers/net/can/rcar/rcar_canfd.c
|
|
@@ -1598,15 +1598,15 @@ static int rcar_canfd_channel_probe(struct rcar_canfd_global *gpriv, u32 ch,
|
|
|
|
netif_napi_add(ndev, &priv->napi, rcar_canfd_rx_poll,
|
|
RCANFD_NAPI_WEIGHT);
|
|
+ spin_lock_init(&priv->tx_lock);
|
|
+ devm_can_led_init(ndev);
|
|
+ gpriv->ch[priv->channel] = priv;
|
|
err = register_candev(ndev);
|
|
if (err) {
|
|
dev_err(&pdev->dev,
|
|
"register_candev() failed, error %d\n", err);
|
|
goto fail_candev;
|
|
}
|
|
- spin_lock_init(&priv->tx_lock);
|
|
- devm_can_led_init(ndev);
|
|
- gpriv->ch[priv->channel] = priv;
|
|
dev_info(&pdev->dev, "device registered (channel %u)\n", priv->channel);
|
|
return 0;
|
|
|
|
diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c
|
|
index 2713300343c7f..ec551def58359 100644
|
|
--- a/drivers/net/ethernet/sfc/mcdi.c
|
|
+++ b/drivers/net/ethernet/sfc/mcdi.c
|
|
@@ -163,9 +163,9 @@ static void efx_mcdi_send_request(struct efx_nic *efx, unsigned cmd,
|
|
/* Serialise with efx_mcdi_ev_cpl() and efx_mcdi_ev_death() */
|
|
spin_lock_bh(&mcdi->iface_lock);
|
|
++mcdi->seqno;
|
|
+ seqno = mcdi->seqno & SEQ_MASK;
|
|
spin_unlock_bh(&mcdi->iface_lock);
|
|
|
|
- seqno = mcdi->seqno & SEQ_MASK;
|
|
xflags = 0;
|
|
if (mcdi->mode == MCDI_MODE_EVENTS)
|
|
xflags |= MCDI_HEADER_XFLAGS_EVREQ;
|
|
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
|
|
index 022f2faccab41..4a433e34ee7a1 100644
|
|
--- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
|
|
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
|
|
@@ -519,8 +519,7 @@ static struct ieee80211_sband_iftype_data iwl_he_capa[] = {
|
|
.has_he = true,
|
|
.he_cap_elem = {
|
|
.mac_cap_info[0] =
|
|
- IEEE80211_HE_MAC_CAP0_HTC_HE |
|
|
- IEEE80211_HE_MAC_CAP0_TWT_REQ,
|
|
+ IEEE80211_HE_MAC_CAP0_HTC_HE,
|
|
.mac_cap_info[1] =
|
|
IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US |
|
|
IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8,
|
|
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
|
|
index 29ad7804d77aa..3c523774ef0e6 100644
|
|
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
|
|
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
|
|
@@ -343,7 +343,6 @@ const static u8 he_if_types_ext_capa_sta[] = {
|
|
[0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING,
|
|
[2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT,
|
|
[7] = WLAN_EXT_CAPA8_OPMODE_NOTIF,
|
|
- [9] = WLAN_EXT_CAPA10_TWT_REQUESTER_SUPPORT,
|
|
};
|
|
|
|
const static struct wiphy_iftype_ext_capab he_iftypes_ext_capa[] = {
|
|
diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h
|
|
index 4e97ba64dbb42..3e6ef64e74d3d 100644
|
|
--- a/include/linux/arm-smccc.h
|
|
+++ b/include/linux/arm-smccc.h
|
|
@@ -76,6 +76,11 @@
|
|
ARM_SMCCC_SMC_32, \
|
|
0, 0x7fff)
|
|
|
|
+#define ARM_SMCCC_ARCH_WORKAROUND_3 \
|
|
+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
|
|
+ ARM_SMCCC_SMC_32, \
|
|
+ 0, 0x3fff)
|
|
+
|
|
#define SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED 1
|
|
|
|
#ifndef __ASSEMBLY__
|
|
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
|
|
index 614f19bbad74f..96faf09186945 100644
|
|
--- a/include/net/xfrm.h
|
|
+++ b/include/net/xfrm.h
|
|
@@ -1663,14 +1663,15 @@ int km_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
|
|
const struct xfrm_migrate *m, int num_bundles,
|
|
const struct xfrm_kmaddress *k,
|
|
const struct xfrm_encap_tmpl *encap);
|
|
-struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net);
|
|
+struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net,
|
|
+ u32 if_id);
|
|
struct xfrm_state *xfrm_state_migrate(struct xfrm_state *x,
|
|
struct xfrm_migrate *m,
|
|
struct xfrm_encap_tmpl *encap);
|
|
int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
|
|
struct xfrm_migrate *m, int num_bundles,
|
|
struct xfrm_kmaddress *k, struct net *net,
|
|
- struct xfrm_encap_tmpl *encap);
|
|
+ struct xfrm_encap_tmpl *encap, u32 if_id);
|
|
#endif
|
|
|
|
int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport);
|
|
diff --git a/lib/Kconfig b/lib/Kconfig
|
|
index 3321d04dfa5a5..fa129b5c4320d 100644
|
|
--- a/lib/Kconfig
|
|
+++ b/lib/Kconfig
|
|
@@ -42,7 +42,6 @@ config BITREVERSE
|
|
config HAVE_ARCH_BITREVERSE
|
|
bool
|
|
default n
|
|
- depends on BITREVERSE
|
|
help
|
|
This option enables the use of hardware bit-reversal instructions on
|
|
architectures which support such operations.
|
|
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
|
|
index 9f53d25e047e3..4815cf72569e0 100644
|
|
--- a/net/ipv4/tcp.c
|
|
+++ b/net/ipv4/tcp.c
|
|
@@ -1652,11 +1652,13 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
|
|
if (!copied)
|
|
copied = used;
|
|
break;
|
|
- } else if (used <= len) {
|
|
- seq += used;
|
|
- copied += used;
|
|
- offset += used;
|
|
}
|
|
+ if (WARN_ON_ONCE(used > len))
|
|
+ used = len;
|
|
+ seq += used;
|
|
+ copied += used;
|
|
+ offset += used;
|
|
+
|
|
/* If recv_actor drops the lock (e.g. TCP splice
|
|
* receive) the skb pointer might be invalid when
|
|
* getting here: tcp_collapse might have deleted it
|
|
diff --git a/net/key/af_key.c b/net/key/af_key.c
|
|
index 907d04a474597..406e13478b01b 100644
|
|
--- a/net/key/af_key.c
|
|
+++ b/net/key/af_key.c
|
|
@@ -2627,7 +2627,7 @@ static int pfkey_migrate(struct sock *sk, struct sk_buff *skb,
|
|
}
|
|
|
|
return xfrm_migrate(&sel, dir, XFRM_POLICY_TYPE_MAIN, m, i,
|
|
- kma ? &k : NULL, net, NULL);
|
|
+ kma ? &k : NULL, net, NULL, 0);
|
|
|
|
out:
|
|
return err;
|
|
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
|
|
index f140c2b94b2c6..f30cdd7f3a73a 100644
|
|
--- a/net/mac80211/agg-tx.c
|
|
+++ b/net/mac80211/agg-tx.c
|
|
@@ -9,7 +9,7 @@
|
|
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
|
|
* Copyright 2007-2010, Intel Corporation
|
|
* Copyright(c) 2015-2017 Intel Deutschland GmbH
|
|
- * Copyright (C) 2018 - 2021 Intel Corporation
|
|
+ * Copyright (C) 2018 - 2022 Intel Corporation
|
|
*/
|
|
|
|
#include <linux/ieee80211.h>
|
|
@@ -615,6 +615,14 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
|
|
return -EINVAL;
|
|
}
|
|
|
|
+ if (test_sta_flag(sta, WLAN_STA_MFP) &&
|
|
+ !test_sta_flag(sta, WLAN_STA_AUTHORIZED)) {
|
|
+ ht_dbg(sdata,
|
|
+ "MFP STA not authorized - deny BA session request %pM tid %d\n",
|
|
+ sta->sta.addr, tid);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
/*
|
|
* 802.11n-2009 11.5.1.1: If the initiating STA is an HT STA, is a
|
|
* member of an IBSS, and has no other existing Block Ack agreement
|
|
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
|
|
index 7c6dcbc8e98ba..1d2f633c6c7c3 100644
|
|
--- a/net/sctp/sm_statefuns.c
|
|
+++ b/net/sctp/sm_statefuns.c
|
|
@@ -149,6 +149,12 @@ static enum sctp_disposition __sctp_sf_do_9_1_abort(
|
|
void *arg,
|
|
struct sctp_cmd_seq *commands);
|
|
|
|
+static enum sctp_disposition
|
|
+__sctp_sf_do_9_2_reshutack(struct net *net, const struct sctp_endpoint *ep,
|
|
+ const struct sctp_association *asoc,
|
|
+ const union sctp_subtype type, void *arg,
|
|
+ struct sctp_cmd_seq *commands);
|
|
+
|
|
/* Small helper function that checks if the chunk length
|
|
* is of the appropriate length. The 'required_length' argument
|
|
* is set to be the size of a specific chunk we are testing.
|
|
@@ -330,6 +336,14 @@ enum sctp_disposition sctp_sf_do_5_1B_init(struct net *net,
|
|
if (!chunk->singleton)
|
|
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
|
|
|
|
+ /* Make sure that the INIT chunk has a valid length.
|
|
+ * Normally, this would cause an ABORT with a Protocol Violation
|
|
+ * error, but since we don't have an association, we'll
|
|
+ * just discard the packet.
|
|
+ */
|
|
+ if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_init_chunk)))
|
|
+ return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
|
|
+
|
|
/* If the packet is an OOTB packet which is temporarily on the
|
|
* control endpoint, respond with an ABORT.
|
|
*/
|
|
@@ -344,14 +358,6 @@ enum sctp_disposition sctp_sf_do_5_1B_init(struct net *net,
|
|
if (chunk->sctp_hdr->vtag != 0)
|
|
return sctp_sf_tabort_8_4_8(net, ep, asoc, type, arg, commands);
|
|
|
|
- /* Make sure that the INIT chunk has a valid length.
|
|
- * Normally, this would cause an ABORT with a Protocol Violation
|
|
- * error, but since we don't have an association, we'll
|
|
- * just discard the packet.
|
|
- */
|
|
- if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_init_chunk)))
|
|
- return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
|
|
-
|
|
/* If the INIT is coming toward a closing socket, we'll send back
|
|
* and ABORT. Essentially, this catches the race of INIT being
|
|
* backloged to the socket at the same time as the user isses close().
|
|
@@ -1484,19 +1490,16 @@ static enum sctp_disposition sctp_sf_do_unexpected_init(
|
|
if (!chunk->singleton)
|
|
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
|
|
|
|
+ /* Make sure that the INIT chunk has a valid length. */
|
|
+ if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_init_chunk)))
|
|
+ return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
|
|
+
|
|
/* 3.1 A packet containing an INIT chunk MUST have a zero Verification
|
|
* Tag.
|
|
*/
|
|
if (chunk->sctp_hdr->vtag != 0)
|
|
return sctp_sf_tabort_8_4_8(net, ep, asoc, type, arg, commands);
|
|
|
|
- /* Make sure that the INIT chunk has a valid length.
|
|
- * In this case, we generate a protocol violation since we have
|
|
- * an association established.
|
|
- */
|
|
- if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_init_chunk)))
|
|
- return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
|
|
- commands);
|
|
/* Grab the INIT header. */
|
|
chunk->subh.init_hdr = (struct sctp_inithdr *)chunk->skb->data;
|
|
|
|
@@ -1814,9 +1817,9 @@ static enum sctp_disposition sctp_sf_do_dupcook_a(
|
|
* its peer.
|
|
*/
|
|
if (sctp_state(asoc, SHUTDOWN_ACK_SENT)) {
|
|
- disposition = sctp_sf_do_9_2_reshutack(net, ep, asoc,
|
|
- SCTP_ST_CHUNK(chunk->chunk_hdr->type),
|
|
- chunk, commands);
|
|
+ disposition = __sctp_sf_do_9_2_reshutack(net, ep, asoc,
|
|
+ SCTP_ST_CHUNK(chunk->chunk_hdr->type),
|
|
+ chunk, commands);
|
|
if (SCTP_DISPOSITION_NOMEM == disposition)
|
|
goto nomem;
|
|
|
|
@@ -2915,13 +2918,11 @@ enum sctp_disposition sctp_sf_do_9_2_shut_ctsn(
|
|
* that belong to this association, it should discard the INIT chunk and
|
|
* retransmit the SHUTDOWN ACK chunk.
|
|
*/
|
|
-enum sctp_disposition sctp_sf_do_9_2_reshutack(
|
|
- struct net *net,
|
|
- const struct sctp_endpoint *ep,
|
|
- const struct sctp_association *asoc,
|
|
- const union sctp_subtype type,
|
|
- void *arg,
|
|
- struct sctp_cmd_seq *commands)
|
|
+static enum sctp_disposition
|
|
+__sctp_sf_do_9_2_reshutack(struct net *net, const struct sctp_endpoint *ep,
|
|
+ const struct sctp_association *asoc,
|
|
+ const union sctp_subtype type, void *arg,
|
|
+ struct sctp_cmd_seq *commands)
|
|
{
|
|
struct sctp_chunk *chunk = arg;
|
|
struct sctp_chunk *reply;
|
|
@@ -2955,6 +2956,26 @@ nomem:
|
|
return SCTP_DISPOSITION_NOMEM;
|
|
}
|
|
|
|
+enum sctp_disposition
|
|
+sctp_sf_do_9_2_reshutack(struct net *net, const struct sctp_endpoint *ep,
|
|
+ const struct sctp_association *asoc,
|
|
+ const union sctp_subtype type, void *arg,
|
|
+ struct sctp_cmd_seq *commands)
|
|
+{
|
|
+ struct sctp_chunk *chunk = arg;
|
|
+
|
|
+ if (!chunk->singleton)
|
|
+ return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
|
|
+
|
|
+ if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_init_chunk)))
|
|
+ return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
|
|
+
|
|
+ if (chunk->sctp_hdr->vtag != 0)
|
|
+ return sctp_sf_tabort_8_4_8(net, ep, asoc, type, arg, commands);
|
|
+
|
|
+ return __sctp_sf_do_9_2_reshutack(net, ep, asoc, type, arg, commands);
|
|
+}
|
|
+
|
|
/*
|
|
* sctp_sf_do_ecn_cwr
|
|
*
|
|
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
|
|
index f2bc465de2845..d3e2b97d5d051 100644
|
|
--- a/net/wireless/nl80211.c
|
|
+++ b/net/wireless/nl80211.c
|
|
@@ -16314,7 +16314,8 @@ void cfg80211_ch_switch_notify(struct net_device *dev,
|
|
wdev->chandef = *chandef;
|
|
wdev->preset_chandef = *chandef;
|
|
|
|
- if (wdev->iftype == NL80211_IFTYPE_STATION &&
|
|
+ if ((wdev->iftype == NL80211_IFTYPE_STATION ||
|
|
+ wdev->iftype == NL80211_IFTYPE_P2P_CLIENT) &&
|
|
!WARN_ON(!wdev->current_bss))
|
|
cfg80211_update_assoc_bss_entry(wdev, chandef->chan);
|
|
|
|
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
|
|
index 404823c5eb7d5..3ecb77c58c44e 100644
|
|
--- a/net/xfrm/xfrm_policy.c
|
|
+++ b/net/xfrm/xfrm_policy.c
|
|
@@ -4271,7 +4271,7 @@ static bool xfrm_migrate_selector_match(const struct xfrm_selector *sel_cmp,
|
|
}
|
|
|
|
static struct xfrm_policy *xfrm_migrate_policy_find(const struct xfrm_selector *sel,
|
|
- u8 dir, u8 type, struct net *net)
|
|
+ u8 dir, u8 type, struct net *net, u32 if_id)
|
|
{
|
|
struct xfrm_policy *pol, *ret = NULL;
|
|
struct hlist_head *chain;
|
|
@@ -4280,7 +4280,8 @@ static struct xfrm_policy *xfrm_migrate_policy_find(const struct xfrm_selector *
|
|
spin_lock_bh(&net->xfrm.xfrm_policy_lock);
|
|
chain = policy_hash_direct(net, &sel->daddr, &sel->saddr, sel->family, dir);
|
|
hlist_for_each_entry(pol, chain, bydst) {
|
|
- if (xfrm_migrate_selector_match(sel, &pol->selector) &&
|
|
+ if ((if_id == 0 || pol->if_id == if_id) &&
|
|
+ xfrm_migrate_selector_match(sel, &pol->selector) &&
|
|
pol->type == type) {
|
|
ret = pol;
|
|
priority = ret->priority;
|
|
@@ -4292,7 +4293,8 @@ static struct xfrm_policy *xfrm_migrate_policy_find(const struct xfrm_selector *
|
|
if ((pol->priority >= priority) && ret)
|
|
break;
|
|
|
|
- if (xfrm_migrate_selector_match(sel, &pol->selector) &&
|
|
+ if ((if_id == 0 || pol->if_id == if_id) &&
|
|
+ xfrm_migrate_selector_match(sel, &pol->selector) &&
|
|
pol->type == type) {
|
|
ret = pol;
|
|
break;
|
|
@@ -4408,7 +4410,7 @@ static int xfrm_migrate_check(const struct xfrm_migrate *m, int num_migrate)
|
|
int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
|
|
struct xfrm_migrate *m, int num_migrate,
|
|
struct xfrm_kmaddress *k, struct net *net,
|
|
- struct xfrm_encap_tmpl *encap)
|
|
+ struct xfrm_encap_tmpl *encap, u32 if_id)
|
|
{
|
|
int i, err, nx_cur = 0, nx_new = 0;
|
|
struct xfrm_policy *pol = NULL;
|
|
@@ -4427,14 +4429,14 @@ int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
|
|
}
|
|
|
|
/* Stage 1 - find policy */
|
|
- if ((pol = xfrm_migrate_policy_find(sel, dir, type, net)) == NULL) {
|
|
+ if ((pol = xfrm_migrate_policy_find(sel, dir, type, net, if_id)) == NULL) {
|
|
err = -ENOENT;
|
|
goto out;
|
|
}
|
|
|
|
/* Stage 2 - find and update state(s) */
|
|
for (i = 0, mp = m; i < num_migrate; i++, mp++) {
|
|
- if ((x = xfrm_migrate_state_find(mp, net))) {
|
|
+ if ((x = xfrm_migrate_state_find(mp, net, if_id))) {
|
|
x_cur[nx_cur] = x;
|
|
nx_cur++;
|
|
xc = xfrm_state_migrate(x, mp, encap);
|
|
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
|
|
index 1423e2b7cb42a..268bba29bb603 100644
|
|
--- a/net/xfrm/xfrm_state.c
|
|
+++ b/net/xfrm/xfrm_state.c
|
|
@@ -1539,9 +1539,6 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig,
|
|
memcpy(&x->mark, &orig->mark, sizeof(x->mark));
|
|
memcpy(&x->props.smark, &orig->props.smark, sizeof(x->props.smark));
|
|
|
|
- if (xfrm_init_state(x) < 0)
|
|
- goto error;
|
|
-
|
|
x->props.flags = orig->props.flags;
|
|
x->props.extra_flags = orig->props.extra_flags;
|
|
|
|
@@ -1563,7 +1560,8 @@ out:
|
|
return NULL;
|
|
}
|
|
|
|
-struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net)
|
|
+struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net,
|
|
+ u32 if_id)
|
|
{
|
|
unsigned int h;
|
|
struct xfrm_state *x = NULL;
|
|
@@ -1579,6 +1577,8 @@ struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *n
|
|
continue;
|
|
if (m->reqid && x->props.reqid != m->reqid)
|
|
continue;
|
|
+ if (if_id != 0 && x->if_id != if_id)
|
|
+ continue;
|
|
if (!xfrm_addr_equal(&x->id.daddr, &m->old_daddr,
|
|
m->old_family) ||
|
|
!xfrm_addr_equal(&x->props.saddr, &m->old_saddr,
|
|
@@ -1594,6 +1594,8 @@ struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *n
|
|
if (x->props.mode != m->mode ||
|
|
x->id.proto != m->proto)
|
|
continue;
|
|
+ if (if_id != 0 && x->if_id != if_id)
|
|
+ continue;
|
|
if (!xfrm_addr_equal(&x->id.daddr, &m->old_daddr,
|
|
m->old_family) ||
|
|
!xfrm_addr_equal(&x->props.saddr, &m->old_saddr,
|
|
@@ -1620,6 +1622,11 @@ struct xfrm_state *xfrm_state_migrate(struct xfrm_state *x,
|
|
if (!xc)
|
|
return NULL;
|
|
|
|
+ xc->props.family = m->new_family;
|
|
+
|
|
+ if (xfrm_init_state(xc) < 0)
|
|
+ goto error;
|
|
+
|
|
memcpy(&xc->id.daddr, &m->new_daddr, sizeof(xc->id.daddr));
|
|
memcpy(&xc->props.saddr, &m->new_saddr, sizeof(xc->props.saddr));
|
|
|
|
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
|
|
index 42ff32700d68b..bd44a800e7db7 100644
|
|
--- a/net/xfrm/xfrm_user.c
|
|
+++ b/net/xfrm/xfrm_user.c
|
|
@@ -621,13 +621,8 @@ static struct xfrm_state *xfrm_state_construct(struct net *net,
|
|
|
|
xfrm_smark_init(attrs, &x->props.smark);
|
|
|
|
- if (attrs[XFRMA_IF_ID]) {
|
|
+ if (attrs[XFRMA_IF_ID])
|
|
x->if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
|
|
- if (!x->if_id) {
|
|
- err = -EINVAL;
|
|
- goto error;
|
|
- }
|
|
- }
|
|
|
|
err = __xfrm_init_state(x, false, attrs[XFRMA_OFFLOAD_DEV]);
|
|
if (err)
|
|
@@ -1333,13 +1328,8 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|
|
|
mark = xfrm_mark_get(attrs, &m);
|
|
|
|
- if (attrs[XFRMA_IF_ID]) {
|
|
+ if (attrs[XFRMA_IF_ID])
|
|
if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
|
|
- if (!if_id) {
|
|
- err = -EINVAL;
|
|
- goto out_noput;
|
|
- }
|
|
- }
|
|
|
|
if (p->info.seq) {
|
|
x = xfrm_find_acq_byseq(net, mark, p->info.seq);
|
|
@@ -1641,13 +1631,8 @@ static struct xfrm_policy *xfrm_policy_construct(struct net *net, struct xfrm_us
|
|
|
|
xfrm_mark_get(attrs, &xp->mark);
|
|
|
|
- if (attrs[XFRMA_IF_ID]) {
|
|
+ if (attrs[XFRMA_IF_ID])
|
|
xp->if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
|
|
- if (!xp->if_id) {
|
|
- err = -EINVAL;
|
|
- goto error;
|
|
- }
|
|
- }
|
|
|
|
return xp;
|
|
error:
|
|
@@ -2389,6 +2374,7 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|
int n = 0;
|
|
struct net *net = sock_net(skb->sk);
|
|
struct xfrm_encap_tmpl *encap = NULL;
|
|
+ u32 if_id = 0;
|
|
|
|
if (attrs[XFRMA_MIGRATE] == NULL)
|
|
return -EINVAL;
|
|
@@ -2413,7 +2399,10 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|
return 0;
|
|
}
|
|
|
|
- err = xfrm_migrate(&pi->sel, pi->dir, type, m, n, kmp, net, encap);
|
|
+ if (attrs[XFRMA_IF_ID])
|
|
+ if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
|
|
+
|
|
+ err = xfrm_migrate(&pi->sel, pi->dir, type, m, n, kmp, net, encap, if_id);
|
|
|
|
kfree(encap);
|
|
|
|
diff --git a/tools/testing/selftests/vm/userfaultfd.c b/tools/testing/selftests/vm/userfaultfd.c
|
|
index 9ba7feffe344b..9814a0a15ba78 100644
|
|
--- a/tools/testing/selftests/vm/userfaultfd.c
|
|
+++ b/tools/testing/selftests/vm/userfaultfd.c
|
|
@@ -46,6 +46,7 @@
|
|
#include <signal.h>
|
|
#include <poll.h>
|
|
#include <string.h>
|
|
+#include <linux/mman.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/syscall.h>
|
|
#include <sys/ioctl.h>
|
|
diff --git a/virt/kvm/arm/psci.c b/virt/kvm/arm/psci.c
|
|
index 48fde38d64c37..2f5dc7fb437bd 100644
|
|
--- a/virt/kvm/arm/psci.c
|
|
+++ b/virt/kvm/arm/psci.c
|
|
@@ -426,6 +426,18 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
|
|
break;
|
|
}
|
|
break;
|
|
+ case ARM_SMCCC_ARCH_WORKAROUND_3:
|
|
+ switch (kvm_arm_get_spectre_bhb_state()) {
|
|
+ case SPECTRE_VULNERABLE:
|
|
+ break;
|
|
+ case SPECTRE_MITIGATED:
|
|
+ val = SMCCC_RET_SUCCESS;
|
|
+ break;
|
|
+ case SPECTRE_UNAFFECTED:
|
|
+ val = SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED;
|
|
+ break;
|
|
+ }
|
|
+ break;
|
|
}
|
|
break;
|
|
default:
|
|
@@ -438,7 +450,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
|
|
|
|
int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
|
|
{
|
|
- return 3; /* PSCI version and two workaround registers */
|
|
+ return 4; /* PSCI version and three workaround registers */
|
|
}
|
|
|
|
int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
|
|
@@ -452,6 +464,9 @@ int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
|
|
if (put_user(KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2, uindices++))
|
|
return -EFAULT;
|
|
|
|
+ if (put_user(KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3, uindices++))
|
|
+ return -EFAULT;
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -486,9 +501,20 @@ static int get_kernel_wa_level(u64 regid)
|
|
return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED;
|
|
case KVM_SSBD_UNKNOWN:
|
|
default:
|
|
- return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN;
|
|
+ break;
|
|
}
|
|
- }
|
|
+ return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN;
|
|
+ case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
|
|
+ switch (kvm_arm_get_spectre_bhb_state()) {
|
|
+ case SPECTRE_VULNERABLE:
|
|
+ return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL;
|
|
+ case SPECTRE_MITIGATED:
|
|
+ return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_AVAIL;
|
|
+ case SPECTRE_UNAFFECTED:
|
|
+ return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_REQUIRED;
|
|
+ }
|
|
+ return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL;
|
|
+ }
|
|
|
|
return -EINVAL;
|
|
}
|
|
@@ -503,6 +529,7 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
|
|
val = kvm_psci_version(vcpu, vcpu->kvm);
|
|
break;
|
|
case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
|
|
+ case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
|
|
val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
|
|
break;
|
|
case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2:
|
|
@@ -555,6 +582,7 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
|
|
}
|
|
|
|
case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
|
|
+ case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
|
|
if (val & ~KVM_REG_FEATURE_LEVEL_MASK)
|
|
return -EINVAL;
|
|
|