This is the 4.19.236 stable release
-----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEZH8oZUiU471FcZm+ONu9yGCSaT4FAmI61hgACgkQONu9yGCS aT7sNRAAwGyljszfWGOcJ46AHzi7TGkvqSNkJQXE4QGFwm2Z4GIqwbe22i3QjjXb Harnnrak7uK+eT780uR2dxnGBcYubYZT8IyPdJts/RaIH3nWHiAj+HpcMrti34ac rVdoLmncXvPDIsEjnhxM2yFlOL0JdyIrmdXUt1j37OmrLF1BKSJpHJHD6DAe2Lqm T3QkThIxH/Z0WHVHnvL+SFPgv7j0LUKtj/7R1MumbSd1mR/wkO2Z5vWUo8CVoInN wJEB96NgcVAYDpmGXdHDEcv5fxx5iBBek8LIOIB5wRX8Y6l52VI4m3qXZo76UooM RQCAfiTsO3pvvsEnXQjYtNkOh9YLke2Vn8/HTZ/EOoekS6Q15wOWZaJxIJQumSD3 Y8VYQofFVUqmSowWdKF+0aBnTrweaSsml0Dm2WsGtWHD5jku7vl8jhCS7x/6V9vd 60GGwwJh5GZqS5NbpdUMcUrTmPo8eTdoraqArZhBId9b74rk1A/WAAGX88yEDJ4q rzC8MD9BEDaKdqikW68j/ROFjhAUGfvVntaClo4PiSqrURJl55LFFi26cU9R2wsH GlgFwtfHW9aB0KSQRwl8/iDcj9nRYa9veSSMAqXoncfTcIddWLcLBQM3Y0T6z84s f0lTAnfkFAPUkGnlJdsA46PqwkveONdNvcvd0C2D4c9eApzJQGo= =uU73 -----END PGP SIGNATURE----- Merge 4.19.236 into android-4.19-stable Changes in 4.19.236 Revert "xfrm: state and policy should fail if XFRMA_IF_ID 0" sctp: fix the processing for INIT chunk sctp: fix the processing for INIT_ACK chunk xfrm: Check if_id in xfrm_migrate xfrm: Fix xfrm migrate issues when address family changes arm64: dts: rockchip: fix rk3399-puma eMMC HS400 signal integrity arm64: dts: rockchip: reorder rk3399 hdmi clocks ARM: dts: rockchip: fix a typo on rk3288 crypto-controller MIPS: smp: fill in sibling and core maps earlier ARM: 9178/1: fix unmet dependency on BITREVERSE for HAVE_ARCH_BITREVERSE can: rcar_canfd: rcar_canfd_channel_probe(): register the CAN device when fully ready atm: firestream: check the return value of ioremap() in fs_init() nl80211: Update bss channel on channel switch for P2P_CLIENT tcp: make tcp_read_sock() more robust sfc: extend the locking on mcdi->seqno kselftest/vm: fix tests build with old libc sched/topology: Make sched_init_numa() use a set for the deduplicating sort sched/topology: Fix sched_domain_topology_level alloc in sched_init_numa() ia64: ensure proper NUMA distance and possible map initialization cpuset: Fix unsafe lock order between cpuset lock and cpuslock mm: fix dereference a null pointer in migrate[_huge]_page_move_mapping() fs: sysfs_emit: Remove PAGE_SIZE alignment check arm64: Add part number for Arm Cortex-A77 arm64: Add Neoverse-N2, Cortex-A710 CPU part definition arm64: Add Cortex-X2 CPU part definition arm64: entry.S: Add ventry overflow sanity checks arm64: entry: Make the trampoline cleanup optional arm64: entry: Free up another register on kpti's tramp_exit path arm64: entry: Move the trampoline data page before the text page arm64: entry: Allow tramp_alias to access symbols after the 4K boundary arm64: entry: Don't assume tramp_vectors is the start of the vectors arm64: entry: Move trampoline macros out of ifdef'd section arm64: entry: Make the kpti trampoline's kpti sequence optional arm64: entry: Allow the trampoline text to occupy multiple pages arm64: entry: Add non-kpti __bp_harden_el1_vectors for mitigations arm64: entry: Add vectors that have the bhb mitigation sequences arm64: entry: Add macro for reading symbol addresses from the trampoline arm64: Add percpu vectors for EL1 arm64: proton-pack: Report Spectre-BHB vulnerabilities as part of Spectre-v2 KVM: arm64: Add templates for BHB mitigation sequences arm64: Mitigate spectre style branch history side channels KVM: arm64: Allow SMCCC_ARCH_WORKAROUND_3 to be discovered and migrated arm64: add ID_AA64ISAR2_EL1 sys register arm64: Use the clearbhb instruction in mitigations crypto: qcom-rng - ensure buffer for generate is completely filled ocfs2: fix crash when initialize filecheck kobj fails efi: fix return value of __setup handlers net/packet: fix slab-out-of-bounds access in packet_recvmsg() atm: eni: Add check for dma_map_single hv_netvsc: Add check for kvmalloc_array drm/panel: simple: Fix Innolux G070Y2-L01 BPP settings net: handle ARPHRD_PIMREG in dev_is_mac_header_xmit() net: dsa: Add missing of_node_put() in dsa_port_parse_of usb: gadget: rndis: prevent integer overflow in rndis_set_response() usb: gadget: Fix use-after-free bug by not setting udc->dev.driver Input: aiptek - properly check endpoint type perf symbols: Fix symbol size calculation condition Linux 4.19.236 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: I03683d55b33b02b7c6f1a0068786de059209747d
This commit is contained in:
commit
086155f9e8
2
Makefile
2
Makefile
@ -1,7 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
VERSION = 4
|
||||
PATCHLEVEL = 19
|
||||
SUBLEVEL = 235
|
||||
SUBLEVEL = 236
|
||||
EXTRAVERSION =
|
||||
NAME = "People's Front"
|
||||
|
||||
|
@ -957,7 +957,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>;
|
||||
|
@ -26,6 +26,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
|
||||
@ -367,4 +368,10 @@ void kvm_arch_free_vm(struct kvm *kvm);
|
||||
|
||||
#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__ */
|
||||
|
@ -1035,6 +1035,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 ARM64_TAGGED_ADDR_ABI
|
||||
bool "Enable the tagged user addresses syscall ABI"
|
||||
default y
|
||||
|
@ -468,6 +468,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;
|
||||
|
@ -1686,10 +1686,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>;
|
||||
|
@ -140,6 +140,13 @@
|
||||
hint #20
|
||||
.endm
|
||||
|
||||
/*
|
||||
* Clear Branch History instruction
|
||||
*/
|
||||
.macro clearbhb
|
||||
hint #22
|
||||
.endm
|
||||
|
||||
/*
|
||||
* Sanitise a 64-bit bounded index wrt speculation, returning zero if out
|
||||
* of bounds.
|
||||
@ -732,4 +739,31 @@ 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\@
|
||||
dsb nsh
|
||||
isb
|
||||
#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 */
|
||||
|
@ -36,6 +36,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;
|
||||
|
@ -54,8 +54,9 @@
|
||||
#define ARM64_WORKAROUND_1463225 33
|
||||
#define ARM64_SSBS 34
|
||||
#define ARM64_WORKAROUND_1542419 35
|
||||
#define ARM64_SPECTRE_BHB 36
|
||||
|
||||
/* kabi: reserve 36 - 62 for future cpu capabilities */
|
||||
/* kabi: reserve 37 - 62 for future cpu capabilities */
|
||||
#define ARM64_NCAPS 62
|
||||
|
||||
#endif /* __ASM_CPUCAPS_H */
|
||||
|
@ -482,6 +482,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);
|
||||
@ -527,6 +555,17 @@ 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);
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#endif
|
||||
|
@ -81,6 +81,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
|
||||
|
||||
@ -109,6 +117,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)
|
||||
|
@ -59,9 +59,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,
|
||||
|
||||
|
@ -542,4 +542,9 @@ void kvm_arch_free_vm(struct kvm *kvm);
|
||||
|
||||
#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__ */
|
||||
|
@ -438,7 +438,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;
|
||||
}
|
||||
@ -467,7 +468,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);
|
||||
}
|
||||
|
@ -38,7 +38,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);
|
||||
@ -49,6 +49,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) || \
|
||||
|
@ -30,4 +30,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 */
|
||||
|
@ -171,6 +171,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)
|
||||
@ -536,6 +537,9 @@
|
||||
#define ID_AA64ISAR1_JSCVT_SHIFT 12
|
||||
#define ID_AA64ISAR1_DPB_SHIFT 0
|
||||
|
||||
/* id_aa64isar2 */
|
||||
#define ID_AA64ISAR2_CLEARBHB_SHIFT 28
|
||||
|
||||
/* id_aa64pfr0 */
|
||||
#define ID_AA64PFR0_CSV3_SHIFT 60
|
||||
#define ID_AA64PFR0_CSV2_SHIFT 56
|
||||
@ -593,6 +597,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
|
||||
|
74
arch/arm64/include/asm/vectors.h
Normal file
74
arch/arm64/include/asm/vectors.h
Normal file
@ -0,0 +1,74 @@
|
||||
/* 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>
|
||||
#include <asm/mmu.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 */
|
@ -24,6 +24,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)
|
||||
@ -97,6 +98,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)
|
||||
@ -110,11 +121,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_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_SPINLOCK(bp_lock);
|
||||
int cpu, slot = -1;
|
||||
|
||||
spin_lock(&bp_lock);
|
||||
@ -133,6 +144,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);
|
||||
spin_unlock(&bp_lock);
|
||||
}
|
||||
#else
|
||||
@ -839,6 +851,13 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
|
||||
.matches = has_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_1463225
|
||||
{
|
||||
.desc = "ARM erratum 1463225",
|
||||
@ -875,14 +894,39 @@ 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)
|
||||
{
|
||||
if (__spectrev2_safe)
|
||||
return sprintf(buf, "Not affected\n");
|
||||
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";
|
||||
|
||||
if (__spectrev2_safe) {
|
||||
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";
|
||||
}
|
||||
|
||||
if (__hardenbp_enab)
|
||||
return sprintf(buf, "Mitigation: Branch predictor hardening\n");
|
||||
return sprintf(buf, "Mitigation: %s%s\n", v2_str, bhb_str);
|
||||
|
||||
return sprintf(buf, "Vulnerable\n");
|
||||
}
|
||||
@ -903,3 +947,332 @@ 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_A77),
|
||||
MIDR_ALL_VERSIONS(MIDR_CORTEX_A76),
|
||||
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:
|
||||
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;
|
||||
|
||||
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);
|
||||
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 (!__spectrev2_safe && !__hardenbp_enab) {
|
||||
/* 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 __init 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);
|
||||
}
|
||||
|
@ -20,11 +20,13 @@
|
||||
|
||||
#include <linux/bsearch.h>
|
||||
#include <linux/cpumask.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>
|
||||
@ -33,6 +35,7 @@
|
||||
#include <asm/processor.h>
|
||||
#include <asm/sysreg.h>
|
||||
#include <asm/traps.h>
|
||||
#include <asm/vectors.h>
|
||||
#include <asm/virt.h>
|
||||
|
||||
unsigned long elf_hwcap __read_mostly;
|
||||
@ -51,6 +54,8 @@ unsigned int compat_elf_hwcap2 __read_mostly;
|
||||
DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS);
|
||||
EXPORT_SYMBOL(cpu_hwcaps);
|
||||
|
||||
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
|
||||
@ -145,6 +150,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),
|
||||
@ -391,6 +401,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),
|
||||
@ -539,6 +550,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);
|
||||
@ -656,6 +668,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
|
||||
@ -789,6 +803,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);
|
||||
@ -963,6 +978,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);
|
||||
}
|
||||
|
||||
if (kpti_applied)
|
||||
return;
|
||||
|
||||
|
@ -345,6 +345,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);
|
||||
|
@ -70,18 +70,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
|
||||
@ -127,11 +130,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
|
||||
@ -352,25 +359,29 @@ 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
|
||||
/*
|
||||
* ARCH_HAS_MEMBARRIER_SYNC_CORE rely on eret context synchronization
|
||||
* when returning from IPI handler, and when returning to user-space.
|
||||
*/
|
||||
|
||||
.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 4f
|
||||
msr far_el1, x30
|
||||
tramp_alias x30, tramp_exit_native
|
||||
msr far_el1, x29
|
||||
tramp_alias x30, tramp_exit_native, x29
|
||||
br x30
|
||||
4:
|
||||
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
|
||||
.endm
|
||||
@ -942,12 +953,7 @@ 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
|
||||
add \tmp, \tmp, #(PAGE_SIZE + RESERVED_TTBR0_SIZE)
|
||||
@ -979,12 +985,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
|
||||
@ -994,43 +1035,75 @@ 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
|
||||
prfm plil1strm, [x30, #(1b - tramp_vectors)]
|
||||
tramp_data_read_var x30, vectors
|
||||
prfm plil1strm, [x30, #(1b - \vector_start)]
|
||||
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
|
||||
.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)
|
||||
@ -1048,11 +1121,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
|
||||
ENTRY(__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 */
|
||||
END(__bp_harden_el1_vectors)
|
||||
.popsection
|
||||
|
||||
|
||||
/*
|
||||
* Register switch for AArch64. The callee-saved registers need to be saved
|
||||
* and restored. On entry:
|
||||
@ -1144,13 +1261,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)
|
||||
@ -1173,12 +1284,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 */
|
||||
|
||||
/*
|
||||
@ -1274,7 +1379,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)
|
||||
|
@ -271,7 +271,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
|
||||
/*
|
||||
|
@ -135,6 +135,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
|
||||
@ -334,4 +338,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
|
||||
|
@ -34,6 +34,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;
|
||||
@ -155,10 +156,13 @@ 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);
|
||||
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);
|
||||
|
||||
|
@ -1289,7 +1289,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),
|
||||
|
@ -600,6 +600,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);
|
||||
|
||||
@ -608,11 +610,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,
|
||||
0);
|
||||
|
||||
/* 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[];
|
||||
|
||||
|
@ -537,7 +537,8 @@ void __init acpi_numa_fixup(void)
|
||||
if (srat_num_cpus == 0) {
|
||||
node_set_online(0);
|
||||
node_cpuid[0].phys_id = hard_smp_processor_id();
|
||||
return;
|
||||
node_distance(0, 0) = LOCAL_DISTANCE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -580,7 +581,7 @@ void __init acpi_numa_fixup(void)
|
||||
for (j = 0; j < MAX_NUMNODES; j++)
|
||||
node_distance(i, j) = i == j ? LOCAL_DISTANCE :
|
||||
REMOTE_DISTANCE;
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memset(numa_slit, -1, sizeof(numa_slit));
|
||||
@ -605,6 +606,8 @@ void __init acpi_numa_fixup(void)
|
||||
printk("\n");
|
||||
}
|
||||
#endif
|
||||
out:
|
||||
node_possible_map = node_online_map;
|
||||
}
|
||||
#endif /* CONFIG_ACPI_NUMA */
|
||||
|
||||
|
@ -372,6 +372,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);
|
||||
|
||||
@ -383,9 +386,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();
|
||||
|
||||
/*
|
||||
|
@ -1114,6 +1114,8 @@ DPRINTK("iovcnt = %d\n",skb_shinfo(skb)->nr_frags);
|
||||
}
|
||||
paddr = dma_map_single(&eni_dev->pci_dev->dev,skb->data,skb->len,
|
||||
DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(&eni_dev->pci_dev->dev, paddr))
|
||||
return enq_next;
|
||||
ENI_PRV_PADDR(skb) = paddr;
|
||||
/* prepare DMA queue entries */
|
||||
j = 0;
|
||||
|
@ -1692,6 +1692,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);
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/crypto.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
@ -42,16 +43,19 @@ static int qcom_rng_read(struct qcom_rng *rng, u8 *data, unsigned int max)
|
||||
{
|
||||
unsigned int currsize = 0;
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
/* read random data from hardware */
|
||||
do {
|
||||
val = readl_relaxed(rng->base + PRNG_STATUS);
|
||||
if (!(val & PRNG_STATUS_DATA_AVAIL))
|
||||
break;
|
||||
ret = readl_poll_timeout(rng->base + PRNG_STATUS, val,
|
||||
val & PRNG_STATUS_DATA_AVAIL,
|
||||
200, 10000);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val = readl_relaxed(rng->base + PRNG_DATA_OUT);
|
||||
if (!val)
|
||||
break;
|
||||
return -EINVAL;
|
||||
|
||||
if ((max - currsize) >= WORD_SZ) {
|
||||
memcpy(data, &val, WORD_SZ);
|
||||
@ -60,11 +64,10 @@ static int qcom_rng_read(struct qcom_rng *rng, u8 *data, unsigned int max)
|
||||
} else {
|
||||
/* copy only remaining bytes */
|
||||
memcpy(data, &val, max - currsize);
|
||||
break;
|
||||
}
|
||||
} while (currsize < max);
|
||||
|
||||
return currsize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcom_rng_generate(struct crypto_rng *tfm,
|
||||
@ -86,7 +89,7 @@ static int qcom_rng_generate(struct crypto_rng *tfm,
|
||||
mutex_unlock(&rng->lock);
|
||||
clk_disable_unprepare(rng->clk);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int qcom_rng_seed(struct crypto_rng *tfm, const u8 *seed,
|
||||
|
@ -34,7 +34,7 @@ static bool dump_properties __initdata;
|
||||
static int __init dump_properties_enable(char *arg)
|
||||
{
|
||||
dump_properties = true;
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
__setup("dump_apple_properties", dump_properties_enable);
|
||||
|
@ -245,7 +245,7 @@ static int __init efivar_ssdt_setup(char *str)
|
||||
memcpy(efivar_ssdt, str, strlen(str));
|
||||
else
|
||||
pr_warn("efivar_ssdt: name too long: %s\n", str);
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
__setup("efivar_ssdt=", efivar_ssdt_setup);
|
||||
|
||||
|
@ -1244,7 +1244,7 @@ static const struct display_timing innolux_g070y2_l01_timing = {
|
||||
static const struct panel_desc innolux_g070y2_l01 = {
|
||||
.timings = &innolux_g070y2_l01_timing,
|
||||
.num_timings = 1,
|
||||
.bpc = 6,
|
||||
.bpc = 8,
|
||||
.size = {
|
||||
.width = 152,
|
||||
.height = 91,
|
||||
|
@ -1814,15 +1814,13 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
input_set_abs_params(inputdev, ABS_TILT_Y, AIPTEK_TILT_MIN, AIPTEK_TILT_MAX, 0, 0);
|
||||
input_set_abs_params(inputdev, ABS_WHEEL, AIPTEK_WHEEL_MIN, AIPTEK_WHEEL_MAX - 1, 0, 0);
|
||||
|
||||
/* Verify that a device really has an endpoint */
|
||||
if (intf->cur_altsetting->desc.bNumEndpoints < 1) {
|
||||
err = usb_find_common_endpoints(intf->cur_altsetting,
|
||||
NULL, NULL, &endpoint, NULL);
|
||||
if (err) {
|
||||
dev_err(&intf->dev,
|
||||
"interface has %d endpoints, but must have minimum 1\n",
|
||||
intf->cur_altsetting->desc.bNumEndpoints);
|
||||
err = -EINVAL;
|
||||
"interface has no int in endpoints, but must have minimum 1\n");
|
||||
goto fail3;
|
||||
}
|
||||
endpoint = &intf->cur_altsetting->endpoint[0].desc;
|
||||
|
||||
/* Go set up our URB, which is called when the tablet receives
|
||||
* input.
|
||||
|
@ -1602,15 +1602,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;
|
||||
|
||||
|
@ -166,9 +166,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;
|
||||
|
@ -1454,6 +1454,9 @@ static void netvsc_get_ethtool_stats(struct net_device *dev,
|
||||
pcpu_sum = kvmalloc_array(num_possible_cpus(),
|
||||
sizeof(struct netvsc_ethtool_pcpu_stats),
|
||||
GFP_KERNEL);
|
||||
if (!pcpu_sum)
|
||||
return;
|
||||
|
||||
netvsc_get_pcpu_stats(dev, pcpu_sum);
|
||||
for_each_present_cpu(cpu) {
|
||||
struct netvsc_ethtool_pcpu_stats *this_sum = &pcpu_sum[cpu];
|
||||
|
@ -640,6 +640,7 @@ static int rndis_set_response(struct rndis_params *params,
|
||||
BufLength = le32_to_cpu(buf->InformationBufferLength);
|
||||
BufOffset = le32_to_cpu(buf->InformationBufferOffset);
|
||||
if ((BufLength > RNDIS_MAX_TOTAL_SIZE) ||
|
||||
(BufOffset > RNDIS_MAX_TOTAL_SIZE) ||
|
||||
(BufOffset + 8 >= RNDIS_MAX_TOTAL_SIZE))
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -1334,7 +1334,6 @@ static void usb_gadget_remove_driver(struct usb_udc *udc)
|
||||
usb_gadget_udc_stop(udc);
|
||||
|
||||
udc->driver = NULL;
|
||||
udc->dev.driver = NULL;
|
||||
udc->gadget->dev.driver = NULL;
|
||||
}
|
||||
|
||||
@ -1383,7 +1382,6 @@ static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *dri
|
||||
driver->function);
|
||||
|
||||
udc->driver = driver;
|
||||
udc->dev.driver = &driver->driver;
|
||||
udc->gadget->dev.driver = &driver->driver;
|
||||
|
||||
usb_gadget_udc_set_speed(udc, driver->max_speed);
|
||||
@ -1405,7 +1403,6 @@ err1:
|
||||
dev_err(&udc->dev, "failed to start %s: %d\n",
|
||||
udc->driver->function, ret);
|
||||
udc->driver = NULL;
|
||||
udc->dev.driver = NULL;
|
||||
udc->gadget->dev.driver = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
@ -1150,17 +1150,6 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
|
||||
goto read_super_error;
|
||||
}
|
||||
|
||||
root = d_make_root(inode);
|
||||
if (!root) {
|
||||
status = -ENOMEM;
|
||||
mlog_errno(status);
|
||||
goto read_super_error;
|
||||
}
|
||||
|
||||
sb->s_root = root;
|
||||
|
||||
ocfs2_complete_mount_recovery(osb);
|
||||
|
||||
osb->osb_dev_kset = kset_create_and_add(sb->s_id, NULL,
|
||||
&ocfs2_kset->kobj);
|
||||
if (!osb->osb_dev_kset) {
|
||||
@ -1178,6 +1167,17 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
|
||||
goto read_super_error;
|
||||
}
|
||||
|
||||
root = d_make_root(inode);
|
||||
if (!root) {
|
||||
status = -ENOMEM;
|
||||
mlog_errno(status);
|
||||
goto read_super_error;
|
||||
}
|
||||
|
||||
sb->s_root = root;
|
||||
|
||||
ocfs2_complete_mount_recovery(osb);
|
||||
|
||||
if (ocfs2_mount_local(osb))
|
||||
snprintf(nodestr, sizeof(nodestr), "local");
|
||||
else
|
||||
|
@ -574,8 +574,7 @@ int sysfs_emit(char *buf, const char *fmt, ...)
|
||||
va_list args;
|
||||
int len;
|
||||
|
||||
if (WARN(!buf || offset_in_page(buf),
|
||||
"invalid sysfs_emit: buf:%p\n", buf))
|
||||
if (WARN(!buf, "invalid sysfs_emit: buf:%p\n", buf))
|
||||
return 0;
|
||||
|
||||
va_start(args, fmt);
|
||||
|
@ -85,6 +85,13 @@
|
||||
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__
|
||||
|
||||
#include <linux/linkage.h>
|
||||
|
@ -55,6 +55,7 @@ static inline bool dev_is_mac_header_xmit(const struct net_device *dev)
|
||||
case ARPHRD_VOID:
|
||||
case ARPHRD_NONE:
|
||||
case ARPHRD_RAWIP:
|
||||
case ARPHRD_PIMREG:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
|
@ -47,6 +47,7 @@ int arch_update_cpu_topology(void);
|
||||
/* Conform to ACPI 2.0 SLIT distance definitions */
|
||||
#define LOCAL_DISTANCE 10
|
||||
#define REMOTE_DISTANCE 20
|
||||
#define DISTANCE_BITS 8
|
||||
#ifndef node_distance
|
||||
#define node_distance(from,to) ((from) == (to) ? LOCAL_DISTANCE : REMOTE_DISTANCE)
|
||||
#endif
|
||||
|
@ -1763,14 +1763,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);
|
||||
|
@ -1537,9 +1537,13 @@ static void cpuset_attach(struct cgroup_taskset *tset)
|
||||
cgroup_taskset_first(tset, &css);
|
||||
cs = css_cs(css);
|
||||
|
||||
cpus_read_lock();
|
||||
mutex_lock(&cpuset_mutex);
|
||||
|
||||
/*
|
||||
* It should hold cpus lock because a cpu offline event can
|
||||
* cause set_cpus_allowed_ptr() failed.
|
||||
*/
|
||||
get_online_cpus();
|
||||
/* prepare for attach */
|
||||
if (cs == &top_cpuset)
|
||||
cpumask_copy(cpus_attach, cpu_possible_mask);
|
||||
@ -1558,6 +1562,7 @@ static void cpuset_attach(struct cgroup_taskset *tset)
|
||||
cpuset_change_task_nodemask(task, &cpuset_attach_nodemask_to);
|
||||
cpuset_update_task_spread_flag(cs, task);
|
||||
}
|
||||
put_online_cpus();
|
||||
|
||||
/*
|
||||
* Change mm for all threadgroup leaders. This is expensive and may
|
||||
@ -1593,7 +1598,6 @@ static void cpuset_attach(struct cgroup_taskset *tset)
|
||||
wake_up(&cpuset_attach_wq);
|
||||
|
||||
mutex_unlock(&cpuset_mutex);
|
||||
cpus_read_unlock();
|
||||
}
|
||||
|
||||
/* The various types of files and directories in a cpuset file system */
|
||||
|
@ -1560,66 +1560,58 @@ static void init_numa_topology_type(void)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define NR_DISTANCE_VALUES (1 << DISTANCE_BITS)
|
||||
|
||||
void sched_init_numa(void)
|
||||
{
|
||||
int next_distance, curr_distance = node_distance(0, 0);
|
||||
struct sched_domain_topology_level *tl;
|
||||
int level = 0;
|
||||
int i, j, k;
|
||||
|
||||
sched_domains_numa_distance = kzalloc(sizeof(int) * (nr_node_ids + 1), GFP_KERNEL);
|
||||
if (!sched_domains_numa_distance)
|
||||
return;
|
||||
|
||||
/* Includes NUMA identity node at level 0. */
|
||||
sched_domains_numa_distance[level++] = curr_distance;
|
||||
sched_domains_numa_levels = level;
|
||||
unsigned long *distance_map;
|
||||
int nr_levels = 0;
|
||||
int i, j;
|
||||
|
||||
/*
|
||||
* O(nr_nodes^2) deduplicating selection sort -- in order to find the
|
||||
* unique distances in the node_distance() table.
|
||||
*
|
||||
* Assumes node_distance(0,j) includes all distances in
|
||||
* node_distance(i,j) in order to avoid cubic time.
|
||||
*/
|
||||
next_distance = curr_distance;
|
||||
distance_map = bitmap_alloc(NR_DISTANCE_VALUES, GFP_KERNEL);
|
||||
if (!distance_map)
|
||||
return;
|
||||
|
||||
bitmap_zero(distance_map, NR_DISTANCE_VALUES);
|
||||
for (i = 0; i < nr_node_ids; i++) {
|
||||
for (j = 0; j < nr_node_ids; j++) {
|
||||
for (k = 0; k < nr_node_ids; k++) {
|
||||
int distance = node_distance(i, k);
|
||||
int distance = node_distance(i, j);
|
||||
|
||||
if (distance > curr_distance &&
|
||||
(distance < next_distance ||
|
||||
next_distance == curr_distance))
|
||||
next_distance = distance;
|
||||
|
||||
/*
|
||||
* While not a strong assumption it would be nice to know
|
||||
* about cases where if node A is connected to B, B is not
|
||||
* equally connected to A.
|
||||
*/
|
||||
if (sched_debug() && node_distance(k, i) != distance)
|
||||
sched_numa_warn("Node-distance not symmetric");
|
||||
|
||||
if (sched_debug() && i && !find_numa_distance(distance))
|
||||
sched_numa_warn("Node-0 not representative");
|
||||
if (distance < LOCAL_DISTANCE || distance >= NR_DISTANCE_VALUES) {
|
||||
sched_numa_warn("Invalid distance value range");
|
||||
return;
|
||||
}
|
||||
if (next_distance != curr_distance) {
|
||||
sched_domains_numa_distance[level++] = next_distance;
|
||||
sched_domains_numa_levels = level;
|
||||
curr_distance = next_distance;
|
||||
} else break;
|
||||
}
|
||||
|
||||
/*
|
||||
* In case of sched_debug() we verify the above assumption.
|
||||
*/
|
||||
if (!sched_debug())
|
||||
break;
|
||||
bitmap_set(distance_map, distance, 1);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* We can now figure out how many unique distance values there are and
|
||||
* allocate memory accordingly.
|
||||
*/
|
||||
nr_levels = bitmap_weight(distance_map, NR_DISTANCE_VALUES);
|
||||
|
||||
sched_domains_numa_distance = kcalloc(nr_levels, sizeof(int), GFP_KERNEL);
|
||||
if (!sched_domains_numa_distance) {
|
||||
bitmap_free(distance_map);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0, j = 0; i < nr_levels; i++, j++) {
|
||||
j = find_next_bit(distance_map, NR_DISTANCE_VALUES, j);
|
||||
sched_domains_numa_distance[i] = j;
|
||||
}
|
||||
|
||||
bitmap_free(distance_map);
|
||||
|
||||
/*
|
||||
* 'level' contains the number of unique distances
|
||||
* 'nr_levels' contains the number of unique distances
|
||||
*
|
||||
* The sched_domains_numa_distance[] array includes the actual distance
|
||||
* numbers.
|
||||
@ -1628,15 +1620,15 @@ void sched_init_numa(void)
|
||||
/*
|
||||
* Here, we should temporarily reset sched_domains_numa_levels to 0.
|
||||
* If it fails to allocate memory for array sched_domains_numa_masks[][],
|
||||
* the array will contain less then 'level' members. This could be
|
||||
* the array will contain less then 'nr_levels' members. This could be
|
||||
* dangerous when we use it to iterate array sched_domains_numa_masks[][]
|
||||
* in other functions.
|
||||
*
|
||||
* We reset it to 'level' at the end of this function.
|
||||
* We reset it to 'nr_levels' at the end of this function.
|
||||
*/
|
||||
sched_domains_numa_levels = 0;
|
||||
|
||||
sched_domains_numa_masks = kzalloc(sizeof(void *) * level, GFP_KERNEL);
|
||||
sched_domains_numa_masks = kzalloc(sizeof(void *) * nr_levels, GFP_KERNEL);
|
||||
if (!sched_domains_numa_masks)
|
||||
return;
|
||||
|
||||
@ -1644,7 +1636,7 @@ void sched_init_numa(void)
|
||||
* Now for each level, construct a mask per node which contains all
|
||||
* CPUs of nodes that are that many hops away from us.
|
||||
*/
|
||||
for (i = 0; i < level; i++) {
|
||||
for (i = 0; i < nr_levels; i++) {
|
||||
sched_domains_numa_masks[i] =
|
||||
kzalloc(nr_node_ids * sizeof(void *), GFP_KERNEL);
|
||||
if (!sched_domains_numa_masks[i])
|
||||
@ -1652,12 +1644,17 @@ void sched_init_numa(void)
|
||||
|
||||
for (j = 0; j < nr_node_ids; j++) {
|
||||
struct cpumask *mask = kzalloc(cpumask_size(), GFP_KERNEL);
|
||||
int k;
|
||||
|
||||
if (!mask)
|
||||
return;
|
||||
|
||||
sched_domains_numa_masks[i][j] = mask;
|
||||
|
||||
for_each_node(k) {
|
||||
if (sched_debug() && (node_distance(j, k) != node_distance(k, j)))
|
||||
sched_numa_warn("Node-distance not symmetric");
|
||||
|
||||
if (node_distance(j, k) > sched_domains_numa_distance[i])
|
||||
continue;
|
||||
|
||||
@ -1669,7 +1666,7 @@ void sched_init_numa(void)
|
||||
/* Compute default topology size */
|
||||
for (i = 0; sched_domain_topology[i].mask; i++);
|
||||
|
||||
tl = kzalloc((i + level + 1) *
|
||||
tl = kzalloc((i + nr_levels + 1) *
|
||||
sizeof(struct sched_domain_topology_level), GFP_KERNEL);
|
||||
if (!tl)
|
||||
return;
|
||||
@ -1692,7 +1689,7 @@ void sched_init_numa(void)
|
||||
/*
|
||||
* .. and append 'j' levels of NUMA goodness.
|
||||
*/
|
||||
for (j = 1; j < level; i++, j++) {
|
||||
for (j = 1; j < nr_levels; i++, j++) {
|
||||
tl[i] = (struct sched_domain_topology_level){
|
||||
.mask = sd_numa_mask,
|
||||
.sd_flags = cpu_numa_flags,
|
||||
@ -1704,8 +1701,8 @@ void sched_init_numa(void)
|
||||
|
||||
sched_domain_topology = tl;
|
||||
|
||||
sched_domains_numa_levels = level;
|
||||
sched_max_numa_distance = sched_domains_numa_distance[level - 1];
|
||||
sched_domains_numa_levels = nr_levels;
|
||||
sched_max_numa_distance = sched_domains_numa_distance[nr_levels - 1];
|
||||
|
||||
init_numa_topology_type();
|
||||
}
|
||||
|
@ -16,7 +16,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.
|
||||
|
@ -472,6 +472,10 @@ int migrate_page_move_mapping(struct address_space *mapping,
|
||||
|
||||
pslot = radix_tree_lookup_slot(&mapping->i_pages,
|
||||
page_index(page));
|
||||
if (pslot == NULL) {
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
expected_count += hpage_nr_pages(page) + page_has_private(page);
|
||||
if (page_count(page) != expected_count ||
|
||||
@ -590,6 +594,10 @@ int migrate_huge_page_move_mapping(struct address_space *mapping,
|
||||
xa_lock_irq(&mapping->i_pages);
|
||||
|
||||
pslot = radix_tree_lookup_slot(&mapping->i_pages, page_index(page));
|
||||
if (pslot == NULL) {
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
expected_count = 2 + page_has_private(page);
|
||||
if (page_count(page) != expected_count ||
|
||||
|
@ -596,6 +596,7 @@ static int dsa_port_parse_of(struct dsa_port *dp, struct device_node *dn)
|
||||
struct net_device *master;
|
||||
|
||||
master = of_find_net_device_by_node(ethernet);
|
||||
of_node_put(ethernet);
|
||||
if (!master)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
|
@ -1669,11 +1669,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
|
||||
|
@ -2633,7 +2633,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;
|
||||
|
@ -2246,8 +2246,11 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
|
||||
copy_skb = skb_get(skb);
|
||||
skb_head = skb->data;
|
||||
}
|
||||
if (copy_skb)
|
||||
if (copy_skb) {
|
||||
memset(&PACKET_SKB_CB(copy_skb)->sa.ll, 0,
|
||||
sizeof(PACKET_SKB_CB(copy_skb)->sa.ll));
|
||||
skb_set_owner_r(copy_skb, sk);
|
||||
}
|
||||
}
|
||||
snaplen = po->rx_ring.frame_size - macoff;
|
||||
if ((int)snaplen < 0) {
|
||||
@ -3406,6 +3409,8 @@ static int packet_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
|
||||
sock_recv_ts_and_drops(msg, sk, skb);
|
||||
|
||||
if (msg->msg_name) {
|
||||
const size_t max_len = min(sizeof(skb->cb),
|
||||
sizeof(struct sockaddr_storage));
|
||||
int copy_len;
|
||||
|
||||
/* If the address length field is there to be filled
|
||||
@ -3428,6 +3433,10 @@ static int packet_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
|
||||
msg->msg_namelen = sizeof(struct sockaddr_ll);
|
||||
}
|
||||
}
|
||||
if (WARN_ON_ONCE(copy_len > max_len)) {
|
||||
copy_len = max_len;
|
||||
msg->msg_namelen = copy_len;
|
||||
}
|
||||
memcpy(msg->msg_name, &PACKET_SKB_CB(skb)->sa, copy_len);
|
||||
}
|
||||
|
||||
|
@ -164,6 +164,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.
|
||||
@ -345,6 +351,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.
|
||||
*/
|
||||
@ -359,14 +373,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().
|
||||
@ -1499,19 +1505,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;
|
||||
|
||||
@ -1829,9 +1832,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;
|
||||
|
||||
@ -2301,7 +2304,7 @@ enum sctp_disposition sctp_sf_shutdown_pending_abort(
|
||||
*/
|
||||
if (SCTP_ADDR_DEL ==
|
||||
sctp_bind_addr_state(&asoc->base.bind_addr, &chunk->dest))
|
||||
return sctp_sf_discard_chunk(net, ep, asoc, type, arg, commands);
|
||||
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
|
||||
|
||||
if (!sctp_err_chunk_valid(chunk))
|
||||
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
|
||||
@ -2347,7 +2350,7 @@ enum sctp_disposition sctp_sf_shutdown_sent_abort(
|
||||
*/
|
||||
if (SCTP_ADDR_DEL ==
|
||||
sctp_bind_addr_state(&asoc->base.bind_addr, &chunk->dest))
|
||||
return sctp_sf_discard_chunk(net, ep, asoc, type, arg, commands);
|
||||
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
|
||||
|
||||
if (!sctp_err_chunk_valid(chunk))
|
||||
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
|
||||
@ -2617,7 +2620,7 @@ enum sctp_disposition sctp_sf_do_9_1_abort(
|
||||
*/
|
||||
if (SCTP_ADDR_DEL ==
|
||||
sctp_bind_addr_state(&asoc->base.bind_addr, &chunk->dest))
|
||||
return sctp_sf_discard_chunk(net, ep, asoc, type, arg, commands);
|
||||
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
|
||||
|
||||
if (!sctp_err_chunk_valid(chunk))
|
||||
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
|
||||
@ -2930,13 +2933,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;
|
||||
@ -2970,6 +2971,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
|
||||
*
|
||||
@ -3766,6 +3787,11 @@ enum sctp_disposition sctp_sf_do_asconf(struct net *net,
|
||||
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
|
||||
}
|
||||
|
||||
/* Make sure that the ASCONF ADDIP chunk has a valid length. */
|
||||
if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_addip_chunk)))
|
||||
return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
|
||||
commands);
|
||||
|
||||
/* ADD-IP: Section 4.1.1
|
||||
* This chunk MUST be sent in an authenticated way by using
|
||||
* the mechanism defined in [I-D.ietf-tsvwg-sctp-auth]. If this chunk
|
||||
@ -3773,13 +3799,7 @@ enum sctp_disposition sctp_sf_do_asconf(struct net *net,
|
||||
* described in [I-D.ietf-tsvwg-sctp-auth].
|
||||
*/
|
||||
if (!net->sctp.addip_noauth && !chunk->auth)
|
||||
return sctp_sf_discard_chunk(net, ep, asoc, type, arg,
|
||||
commands);
|
||||
|
||||
/* Make sure that the ASCONF ADDIP chunk has a valid length. */
|
||||
if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_addip_chunk)))
|
||||
return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
|
||||
commands);
|
||||
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
|
||||
|
||||
hdr = (struct sctp_addiphdr *)chunk->skb->data;
|
||||
serial = ntohl(hdr->serial);
|
||||
@ -3908,6 +3928,12 @@ enum sctp_disposition sctp_sf_do_asconf_ack(struct net *net,
|
||||
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
|
||||
}
|
||||
|
||||
/* Make sure that the ADDIP chunk has a valid length. */
|
||||
if (!sctp_chunk_length_valid(asconf_ack,
|
||||
sizeof(struct sctp_addip_chunk)))
|
||||
return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
|
||||
commands);
|
||||
|
||||
/* ADD-IP, Section 4.1.2:
|
||||
* This chunk MUST be sent in an authenticated way by using
|
||||
* the mechanism defined in [I-D.ietf-tsvwg-sctp-auth]. If this chunk
|
||||
@ -3915,14 +3941,7 @@ enum sctp_disposition sctp_sf_do_asconf_ack(struct net *net,
|
||||
* described in [I-D.ietf-tsvwg-sctp-auth].
|
||||
*/
|
||||
if (!net->sctp.addip_noauth && !asconf_ack->auth)
|
||||
return sctp_sf_discard_chunk(net, ep, asoc, type, arg,
|
||||
commands);
|
||||
|
||||
/* Make sure that the ADDIP chunk has a valid length. */
|
||||
if (!sctp_chunk_length_valid(asconf_ack,
|
||||
sizeof(struct sctp_addip_chunk)))
|
||||
return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
|
||||
commands);
|
||||
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
|
||||
|
||||
addip_hdr = (struct sctp_addiphdr *)asconf_ack->skb->data;
|
||||
rcvd_serial = ntohl(addip_hdr->serial);
|
||||
@ -4494,6 +4513,9 @@ enum sctp_disposition sctp_sf_discard_chunk(struct net *net,
|
||||
{
|
||||
struct sctp_chunk *chunk = arg;
|
||||
|
||||
if (asoc && !sctp_vtag_verify(chunk, asoc))
|
||||
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
|
||||
|
||||
/* Make sure that the chunk has a valid length.
|
||||
* Since we don't know the chunk type, we use a general
|
||||
* chunkhdr structure to make a comparison.
|
||||
|
@ -15685,7 +15685,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))
|
||||
wdev->current_bss->pub.channel = chandef->chan;
|
||||
|
||||
|
@ -3050,7 +3050,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;
|
||||
@ -3059,7 +3059,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;
|
||||
@ -3071,7 +3072,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;
|
||||
@ -3187,7 +3189,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;
|
||||
@ -3206,14 +3208,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);
|
||||
|
@ -1443,9 +1443,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;
|
||||
|
||||
@ -1467,7 +1464,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;
|
||||
@ -1483,6 +1481,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,
|
||||
@ -1498,6 +1498,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,
|
||||
@ -1524,6 +1526,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));
|
||||
|
||||
|
@ -2418,6 +2418,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;
|
||||
@ -2442,7 +2443,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);
|
||||
|
||||
|
@ -217,7 +217,7 @@ void symbols__fixup_end(struct rb_root *symbols)
|
||||
prev = curr;
|
||||
curr = rb_entry(nd, struct symbol, rb_node);
|
||||
|
||||
if (prev->end == prev->start && prev->end != curr->start)
|
||||
if (prev->end == prev->start || prev->end != curr->start)
|
||||
arch__symbols__fixup_end(prev, curr);
|
||||
}
|
||||
|
||||
|
@ -60,6 +60,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>
|
||||
|
@ -429,6 +429,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:
|
||||
|
Loading…
Reference in New Issue
Block a user