On 4/28/2019 9:19 AM, Michael Ellerman wrote: > Diana Madalina Craciun <diana.craciun@xxxxxxx> writes: >> Hi Michael, >> >> There are some missing NXP Spectre v2 patches. I can send them >> separately if the series will be accepted. I have merged them, but I did >> not test them, I was sick today and incapable of doing that. > No worries, there's no rush :) > > Sorry I missed them, I thought I had a list that included everything. > Which commits was it I missed? > > I guess post them as a reply to this thread? That way whether the series > is merged by Greg or not, there's a record here of what the backports > look like. I have sent them as a separate series, but mentioning them here as well: Diana Craciun (8): powerpc/fsl: Enable runtime patching if nospectre_v2 boot arg is used powerpc/fsl: Flush branch predictor when entering KVM powerpc/fsl: Emulate SPRN_BUCSR register powerpc/fsl: Flush the branch predictor at each kernel entry (32 bit) powerpc/fsl: Sanitize the syscall table for NXP PowerPC 32 bit platforms powerpc/fsl: Fixed warning: orphan section `__btb_flush_fixup' powerpc/fsl: Add FSL_PPC_BOOK3E as supported arch for nospectre_v2 boot arg Documentation: Add nospectre_v1 parameter regards > cheers > >> On 4/21/2019 5:21 PM, Michael Ellerman wrote: >>> -----BEGIN PGP SIGNED MESSAGE----- >>> Hash: SHA1 >>> >>> Hi Greg/Sasha, >>> >>> Please queue up these powerpc patches for 4.4 if you have no objections. >>> >>> cheers >>> >>> >>> Christophe Leroy (1): >>> powerpc/fsl: Fix the flush of branch predictor. >>> >>> Diana Craciun (10): >>> powerpc/64: Disable the speculation barrier from the command line >>> powerpc/64: Make stf barrier PPC_BOOK3S_64 specific. >>> powerpc/64: Make meltdown reporting Book3S 64 specific >>> powerpc/fsl: Add barrier_nospec implementation for NXP PowerPC Book3E >>> powerpc/fsl: Add infrastructure to fixup branch predictor flush >>> powerpc/fsl: Add macro to flush the branch predictor >>> powerpc/fsl: Fix spectre_v2 mitigations reporting >>> powerpc/fsl: Add nospectre_v2 command line argument >>> powerpc/fsl: Flush the branch predictor at each kernel entry (64bit) >>> powerpc/fsl: Update Spectre v2 reporting >>> >>> Mauricio Faria de Oliveira (4): >>> powerpc/rfi-flush: Differentiate enabled and patched flush types >>> powerpc/pseries: Fix clearing of security feature flags >>> powerpc: Move default security feature flags >>> powerpc/pseries: Restore default security feature flags on setup >>> >>> Michael Ellerman (29): >>> powerpc/xmon: Add RFI flush related fields to paca dump >>> powerpc/pseries: Support firmware disable of RFI flush >>> powerpc/powernv: Support firmware disable of RFI flush >>> powerpc/rfi-flush: Move the logic to avoid a redo into the debugfs >>> code >>> powerpc/rfi-flush: Make it possible to call setup_rfi_flush() again >>> powerpc/rfi-flush: Always enable fallback flush on pseries >>> powerpc/pseries: Add new H_GET_CPU_CHARACTERISTICS flags >>> powerpc/rfi-flush: Call setup_rfi_flush() after LPM migration >>> powerpc: Add security feature flags for Spectre/Meltdown >>> powerpc/pseries: Set or clear security feature flags >>> powerpc/powernv: Set or clear security feature flags >>> powerpc/64s: Move cpu_show_meltdown() >>> powerpc/64s: Enhance the information in cpu_show_meltdown() >>> powerpc/powernv: Use the security flags in pnv_setup_rfi_flush() >>> powerpc/pseries: Use the security flags in pseries_setup_rfi_flush() >>> powerpc/64s: Wire up cpu_show_spectre_v1() >>> powerpc/64s: Wire up cpu_show_spectre_v2() >>> powerpc/64s: Fix section mismatch warnings from setup_rfi_flush() >>> powerpc/64: Use barrier_nospec in syscall entry >>> powerpc: Use barrier_nospec in copy_from_user() >>> powerpc64s: Show ori31 availability in spectre_v1 sysfs file not v2 >>> powerpc/64: Add CONFIG_PPC_BARRIER_NOSPEC >>> powerpc/64: Call setup_barrier_nospec() from setup_arch() >>> powerpc/asm: Add a patch_site macro & helpers for patching >>> instructions >>> powerpc/64s: Add new security feature flags for count cache flush >>> powerpc/64s: Add support for software count cache flush >>> powerpc/pseries: Query hypervisor for count cache flush settings >>> powerpc/powernv: Query firmware for count cache flush settings >>> powerpc/security: Fix spectre_v2 reporting >>> >>> Michael Neuling (1): >>> powerpc: Avoid code patching freed init sections >>> >>> Michal Suchanek (5): >>> powerpc/64s: Add barrier_nospec >>> powerpc/64s: Add support for ori barrier_nospec patching >>> powerpc/64s: Patch barrier_nospec in modules >>> powerpc/64s: Enable barrier_nospec based on firmware settings >>> powerpc/64s: Enhance the information in cpu_show_spectre_v1() >>> >>> Nicholas Piggin (2): >>> powerpc/64s: Improve RFI L1-D cache flush fallback >>> powerpc/64s: Add support for a store forwarding barrier at kernel >>> entry/exit >>> >>> arch/powerpc/Kconfig | 7 +- >>> arch/powerpc/include/asm/asm-prototypes.h | 21 + >>> arch/powerpc/include/asm/barrier.h | 21 + >>> arch/powerpc/include/asm/code-patching-asm.h | 18 + >>> arch/powerpc/include/asm/code-patching.h | 2 + >>> arch/powerpc/include/asm/exception-64s.h | 35 ++ >>> arch/powerpc/include/asm/feature-fixups.h | 40 ++ >>> arch/powerpc/include/asm/hvcall.h | 5 + >>> arch/powerpc/include/asm/paca.h | 3 +- >>> arch/powerpc/include/asm/ppc-opcode.h | 1 + >>> arch/powerpc/include/asm/ppc_asm.h | 11 + >>> arch/powerpc/include/asm/security_features.h | 92 ++++ >>> arch/powerpc/include/asm/setup.h | 23 +- >>> arch/powerpc/include/asm/uaccess.h | 18 +- >>> arch/powerpc/kernel/Makefile | 1 + >>> arch/powerpc/kernel/asm-offsets.c | 3 +- >>> arch/powerpc/kernel/entry_64.S | 69 +++ >>> arch/powerpc/kernel/exceptions-64e.S | 27 +- >>> arch/powerpc/kernel/exceptions-64s.S | 98 +++-- >>> arch/powerpc/kernel/module.c | 10 +- >>> arch/powerpc/kernel/security.c | 433 +++++++++++++++++++ >>> arch/powerpc/kernel/setup_32.c | 2 + >>> arch/powerpc/kernel/setup_64.c | 50 +-- >>> arch/powerpc/kernel/vmlinux.lds.S | 33 +- >>> arch/powerpc/lib/code-patching.c | 29 ++ >>> arch/powerpc/lib/feature-fixups.c | 218 +++++++++- >>> arch/powerpc/mm/mem.c | 2 + >>> arch/powerpc/mm/tlb_low_64e.S | 7 + >>> arch/powerpc/platforms/powernv/setup.c | 99 +++-- >>> arch/powerpc/platforms/pseries/mobility.c | 3 + >>> arch/powerpc/platforms/pseries/pseries.h | 2 + >>> arch/powerpc/platforms/pseries/setup.c | 88 +++- >>> arch/powerpc/xmon/xmon.c | 2 + >>> 33 files changed, 1345 insertions(+), 128 deletions(-) >>> create mode 100644 arch/powerpc/include/asm/asm-prototypes.h >>> create mode 100644 arch/powerpc/include/asm/code-patching-asm.h >>> create mode 100644 arch/powerpc/include/asm/security_features.h >>> create mode 100644 arch/powerpc/kernel/security.c >>> >>> diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig >>> index 58a1fa979655..01b6c00a7060 100644 >>> - --- a/arch/powerpc/Kconfig >>> +++ b/arch/powerpc/Kconfig >>> @@ -136,7 +136,7 @@ config PPC >>> select GENERIC_SMP_IDLE_THREAD >>> select GENERIC_CMOS_UPDATE >>> select GENERIC_TIME_VSYSCALL_OLD >>> - - select GENERIC_CPU_VULNERABILITIES if PPC_BOOK3S_64 >>> + select GENERIC_CPU_VULNERABILITIES if PPC_BARRIER_NOSPEC >>> select GENERIC_CLOCKEVENTS >>> select GENERIC_CLOCKEVENTS_BROADCAST if SMP >>> select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST >>> @@ -162,6 +162,11 @@ config PPC >>> select ARCH_HAS_DMA_SET_COHERENT_MASK >>> select HAVE_ARCH_SECCOMP_FILTER >>> >>> +config PPC_BARRIER_NOSPEC >>> + bool >>> + default y >>> + depends on PPC_BOOK3S_64 || PPC_FSL_BOOK3E >>> + >>> config GENERIC_CSUM >>> def_bool CPU_LITTLE_ENDIAN >>> >>> diff --git a/arch/powerpc/include/asm/asm-prototypes.h b/arch/powerpc/include/asm/asm-prototypes.h >>> new file mode 100644 >>> index 000000000000..8944c55591cf >>> - --- /dev/null >>> +++ b/arch/powerpc/include/asm/asm-prototypes.h >>> @@ -0,0 +1,21 @@ >>> +#ifndef _ASM_POWERPC_ASM_PROTOTYPES_H >>> +#define _ASM_POWERPC_ASM_PROTOTYPES_H >>> +/* >>> + * This file is for prototypes of C functions that are only called >>> + * from asm, and any associated variables. >>> + * >>> + * Copyright 2016, Daniel Axtens, IBM Corporation. >>> + * >>> + * This program is free software; you can redistribute it and/or >>> + * modify it under the terms of the GNU General Public License >>> + * as published by the Free Software Foundation; either version 2 >>> + * of the License, or (at your option) any later version. >>> + */ >>> + >>> +/* Patch sites */ >>> +extern s32 patch__call_flush_count_cache; >>> +extern s32 patch__flush_count_cache_return; >>> + >>> +extern long flush_count_cache; >>> + >>> +#endif /* _ASM_POWERPC_ASM_PROTOTYPES_H */ >>> diff --git a/arch/powerpc/include/asm/barrier.h b/arch/powerpc/include/asm/barrier.h >>> index b9e16855a037..e7cb72cdb2ba 100644 >>> - --- a/arch/powerpc/include/asm/barrier.h >>> +++ b/arch/powerpc/include/asm/barrier.h >>> @@ -92,4 +92,25 @@ do { \ >>> #define smp_mb__after_atomic() smp_mb() >>> #define smp_mb__before_spinlock() smp_mb() >>> >>> +#ifdef CONFIG_PPC_BOOK3S_64 >>> +#define NOSPEC_BARRIER_SLOT nop >>> +#elif defined(CONFIG_PPC_FSL_BOOK3E) >>> +#define NOSPEC_BARRIER_SLOT nop; nop >>> +#endif >>> + >>> +#ifdef CONFIG_PPC_BARRIER_NOSPEC >>> +/* >>> + * Prevent execution of subsequent instructions until preceding branches have >>> + * been fully resolved and are no longer executing speculatively. >>> + */ >>> +#define barrier_nospec_asm NOSPEC_BARRIER_FIXUP_SECTION; NOSPEC_BARRIER_SLOT >>> + >>> +// This also acts as a compiler barrier due to the memory clobber. >>> +#define barrier_nospec() asm (stringify_in_c(barrier_nospec_asm) ::: "memory") >>> + >>> +#else /* !CONFIG_PPC_BARRIER_NOSPEC */ >>> +#define barrier_nospec_asm >>> +#define barrier_nospec() >>> +#endif /* CONFIG_PPC_BARRIER_NOSPEC */ >>> + >>> #endif /* _ASM_POWERPC_BARRIER_H */ >>> diff --git a/arch/powerpc/include/asm/code-patching-asm.h b/arch/powerpc/include/asm/code-patching-asm.h >>> new file mode 100644 >>> index 000000000000..ed7b1448493a >>> - --- /dev/null >>> +++ b/arch/powerpc/include/asm/code-patching-asm.h >>> @@ -0,0 +1,18 @@ >>> +/* SPDX-License-Identifier: GPL-2.0+ */ >>> +/* >>> + * Copyright 2018, Michael Ellerman, IBM Corporation. >>> + */ >>> +#ifndef _ASM_POWERPC_CODE_PATCHING_ASM_H >>> +#define _ASM_POWERPC_CODE_PATCHING_ASM_H >>> + >>> +/* Define a "site" that can be patched */ >>> +.macro patch_site label name >>> + .pushsection ".rodata" >>> + .balign 4 >>> + .global \name >>> +\name: >>> + .4byte \label - . >>> + .popsection >>> +.endm >>> + >>> +#endif /* _ASM_POWERPC_CODE_PATCHING_ASM_H */ >>> diff --git a/arch/powerpc/include/asm/code-patching.h b/arch/powerpc/include/asm/code-patching.h >>> index 840a5509b3f1..a734b4b34d26 100644 >>> - --- a/arch/powerpc/include/asm/code-patching.h >>> +++ b/arch/powerpc/include/asm/code-patching.h >>> @@ -28,6 +28,8 @@ unsigned int create_cond_branch(const unsigned int *addr, >>> unsigned long target, int flags); >>> int patch_branch(unsigned int *addr, unsigned long target, int flags); >>> int patch_instruction(unsigned int *addr, unsigned int instr); >>> +int patch_instruction_site(s32 *addr, unsigned int instr); >>> +int patch_branch_site(s32 *site, unsigned long target, int flags); >>> >>> int instr_is_relative_branch(unsigned int instr); >>> int instr_is_branch_to_addr(const unsigned int *instr, unsigned long addr); >>> diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h >>> index 9bddbec441b8..3ed536bec462 100644 >>> - --- a/arch/powerpc/include/asm/exception-64s.h >>> +++ b/arch/powerpc/include/asm/exception-64s.h >>> @@ -50,6 +50,27 @@ >>> #define EX_PPR 88 /* SMT thread status register (priority) */ >>> #define EX_CTR 96 >>> >>> +#define STF_ENTRY_BARRIER_SLOT \ >>> + STF_ENTRY_BARRIER_FIXUP_SECTION; \ >>> + nop; \ >>> + nop; \ >>> + nop >>> + >>> +#define STF_EXIT_BARRIER_SLOT \ >>> + STF_EXIT_BARRIER_FIXUP_SECTION; \ >>> + nop; \ >>> + nop; \ >>> + nop; \ >>> + nop; \ >>> + nop; \ >>> + nop >>> + >>> +/* >>> + * r10 must be free to use, r13 must be paca >>> + */ >>> +#define INTERRUPT_TO_KERNEL \ >>> + STF_ENTRY_BARRIER_SLOT >>> + >>> /* >>> * Macros for annotating the expected destination of (h)rfid >>> * >>> @@ -66,16 +87,19 @@ >>> rfid >>> >>> #define RFI_TO_USER \ >>> + STF_EXIT_BARRIER_SLOT; \ >>> RFI_FLUSH_SLOT; \ >>> rfid; \ >>> b rfi_flush_fallback >>> >>> #define RFI_TO_USER_OR_KERNEL \ >>> + STF_EXIT_BARRIER_SLOT; \ >>> RFI_FLUSH_SLOT; \ >>> rfid; \ >>> b rfi_flush_fallback >>> >>> #define RFI_TO_GUEST \ >>> + STF_EXIT_BARRIER_SLOT; \ >>> RFI_FLUSH_SLOT; \ >>> rfid; \ >>> b rfi_flush_fallback >>> @@ -84,21 +108,25 @@ >>> hrfid >>> >>> #define HRFI_TO_USER \ >>> + STF_EXIT_BARRIER_SLOT; \ >>> RFI_FLUSH_SLOT; \ >>> hrfid; \ >>> b hrfi_flush_fallback >>> >>> #define HRFI_TO_USER_OR_KERNEL \ >>> + STF_EXIT_BARRIER_SLOT; \ >>> RFI_FLUSH_SLOT; \ >>> hrfid; \ >>> b hrfi_flush_fallback >>> >>> #define HRFI_TO_GUEST \ >>> + STF_EXIT_BARRIER_SLOT; \ >>> RFI_FLUSH_SLOT; \ >>> hrfid; \ >>> b hrfi_flush_fallback >>> >>> #define HRFI_TO_UNKNOWN \ >>> + STF_EXIT_BARRIER_SLOT; \ >>> RFI_FLUSH_SLOT; \ >>> hrfid; \ >>> b hrfi_flush_fallback >>> @@ -226,6 +254,7 @@ END_FTR_SECTION_NESTED(ftr,ftr,943) >>> #define __EXCEPTION_PROLOG_1(area, extra, vec) \ >>> OPT_SAVE_REG_TO_PACA(area+EX_PPR, r9, CPU_FTR_HAS_PPR); \ >>> OPT_SAVE_REG_TO_PACA(area+EX_CFAR, r10, CPU_FTR_CFAR); \ >>> + INTERRUPT_TO_KERNEL; \ >>> SAVE_CTR(r10, area); \ >>> mfcr r9; \ >>> extra(vec); \ >>> @@ -512,6 +541,12 @@ label##_relon_hv: \ >>> #define _MASKABLE_EXCEPTION_PSERIES(vec, label, h, extra) \ >>> __MASKABLE_EXCEPTION_PSERIES(vec, label, h, extra) >>> >>> +#define MASKABLE_EXCEPTION_OOL(vec, label) \ >>> + .globl label##_ool; \ >>> +label##_ool: \ >>> + EXCEPTION_PROLOG_1(PACA_EXGEN, SOFTEN_TEST_PR, vec); \ >>> + EXCEPTION_PROLOG_PSERIES_1(label##_common, EXC_STD); >>> + >>> #define MASKABLE_EXCEPTION_PSERIES(loc, vec, label) \ >>> . = loc; \ >>> .globl label##_pSeries; \ >>> diff --git a/arch/powerpc/include/asm/feature-fixups.h b/arch/powerpc/include/asm/feature-fixups.h >>> index 7068bafbb2d6..145a37ab2d3e 100644 >>> - --- a/arch/powerpc/include/asm/feature-fixups.h >>> +++ b/arch/powerpc/include/asm/feature-fixups.h >>> @@ -184,6 +184,22 @@ label##3: \ >>> FTR_ENTRY_OFFSET label##1b-label##3b; \ >>> .popsection; >>> >>> +#define STF_ENTRY_BARRIER_FIXUP_SECTION \ >>> +953: \ >>> + .pushsection __stf_entry_barrier_fixup,"a"; \ >>> + .align 2; \ >>> +954: \ >>> + FTR_ENTRY_OFFSET 953b-954b; \ >>> + .popsection; >>> + >>> +#define STF_EXIT_BARRIER_FIXUP_SECTION \ >>> +955: \ >>> + .pushsection __stf_exit_barrier_fixup,"a"; \ >>> + .align 2; \ >>> +956: \ >>> + FTR_ENTRY_OFFSET 955b-956b; \ >>> + .popsection; >>> + >>> #define RFI_FLUSH_FIXUP_SECTION \ >>> 951: \ >>> .pushsection __rfi_flush_fixup,"a"; \ >>> @@ -192,10 +208,34 @@ label##3: \ >>> FTR_ENTRY_OFFSET 951b-952b; \ >>> .popsection; >>> >>> +#define NOSPEC_BARRIER_FIXUP_SECTION \ >>> +953: \ >>> + .pushsection __barrier_nospec_fixup,"a"; \ >>> + .align 2; \ >>> +954: \ >>> + FTR_ENTRY_OFFSET 953b-954b; \ >>> + .popsection; >>> + >>> +#define START_BTB_FLUSH_SECTION \ >>> +955: \ >>> + >>> +#define END_BTB_FLUSH_SECTION \ >>> +956: \ >>> + .pushsection __btb_flush_fixup,"a"; \ >>> + .align 2; \ >>> +957: \ >>> + FTR_ENTRY_OFFSET 955b-957b; \ >>> + FTR_ENTRY_OFFSET 956b-957b; \ >>> + .popsection; >>> >>> #ifndef __ASSEMBLY__ >>> >>> +extern long stf_barrier_fallback; >>> +extern long __start___stf_entry_barrier_fixup, __stop___stf_entry_barrier_fixup; >>> +extern long __start___stf_exit_barrier_fixup, __stop___stf_exit_barrier_fixup; >>> extern long __start___rfi_flush_fixup, __stop___rfi_flush_fixup; >>> +extern long __start___barrier_nospec_fixup, __stop___barrier_nospec_fixup; >>> +extern long __start__btb_flush_fixup, __stop__btb_flush_fixup; >>> >>> #endif >>> >>> diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h >>> index 449bbb87c257..b57db9d09db9 100644 >>> - --- a/arch/powerpc/include/asm/hvcall.h >>> +++ b/arch/powerpc/include/asm/hvcall.h >>> @@ -292,10 +292,15 @@ >>> #define H_CPU_CHAR_L1D_FLUSH_ORI30 (1ull << 61) // IBM bit 2 >>> #define H_CPU_CHAR_L1D_FLUSH_TRIG2 (1ull << 60) // IBM bit 3 >>> #define H_CPU_CHAR_L1D_THREAD_PRIV (1ull << 59) // IBM bit 4 >>> +#define H_CPU_CHAR_BRANCH_HINTS_HONORED (1ull << 58) // IBM bit 5 >>> +#define H_CPU_CHAR_THREAD_RECONFIG_CTRL (1ull << 57) // IBM bit 6 >>> +#define H_CPU_CHAR_COUNT_CACHE_DISABLED (1ull << 56) // IBM bit 7 >>> +#define H_CPU_CHAR_BCCTR_FLUSH_ASSIST (1ull << 54) // IBM bit 9 >>> >>> #define H_CPU_BEHAV_FAVOUR_SECURITY (1ull << 63) // IBM bit 0 >>> #define H_CPU_BEHAV_L1D_FLUSH_PR (1ull << 62) // IBM bit 1 >>> #define H_CPU_BEHAV_BNDS_CHK_SPEC_BAR (1ull << 61) // IBM bit 2 >>> +#define H_CPU_BEHAV_FLUSH_COUNT_CACHE (1ull << 58) // IBM bit 5 >>> >>> #ifndef __ASSEMBLY__ >>> #include <linux/types.h> >>> diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h >>> index 45e2aefece16..08e5df3395fa 100644 >>> - --- a/arch/powerpc/include/asm/paca.h >>> +++ b/arch/powerpc/include/asm/paca.h >>> @@ -199,8 +199,7 @@ struct paca_struct { >>> */ >>> u64 exrfi[13] __aligned(0x80); >>> void *rfi_flush_fallback_area; >>> - - u64 l1d_flush_congruence; >>> - - u64 l1d_flush_sets; >>> + u64 l1d_flush_size; >>> #endif >>> }; >>> >>> diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h >>> index 7ab04fc59e24..faf1bb045dee 100644 >>> - --- a/arch/powerpc/include/asm/ppc-opcode.h >>> +++ b/arch/powerpc/include/asm/ppc-opcode.h >>> @@ -147,6 +147,7 @@ >>> #define PPC_INST_LWSYNC 0x7c2004ac >>> #define PPC_INST_SYNC 0x7c0004ac >>> #define PPC_INST_SYNC_MASK 0xfc0007fe >>> +#define PPC_INST_ISYNC 0x4c00012c >>> #define PPC_INST_LXVD2X 0x7c000698 >>> #define PPC_INST_MCRXR 0x7c000400 >>> #define PPC_INST_MCRXR_MASK 0xfc0007fe >>> diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h >>> index 160bb2311bbb..d219816b3e19 100644 >>> - --- a/arch/powerpc/include/asm/ppc_asm.h >>> +++ b/arch/powerpc/include/asm/ppc_asm.h >>> @@ -821,4 +821,15 @@ END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,CPU_FTR_HAS_PPR,945) >>> .long 0x2400004c /* rfid */ >>> #endif /* !CONFIG_PPC_BOOK3E */ >>> #endif /* __ASSEMBLY__ */ >>> + >>> +#ifdef CONFIG_PPC_FSL_BOOK3E >>> +#define BTB_FLUSH(reg) \ >>> + lis reg,BUCSR_INIT@h; \ >>> + ori reg,reg,BUCSR_INIT@l; \ >>> + mtspr SPRN_BUCSR,reg; \ >>> + isync; >>> +#else >>> +#define BTB_FLUSH(reg) >>> +#endif /* CONFIG_PPC_FSL_BOOK3E */ >>> + >>> #endif /* _ASM_POWERPC_PPC_ASM_H */ >>> diff --git a/arch/powerpc/include/asm/security_features.h b/arch/powerpc/include/asm/security_features.h >>> new file mode 100644 >>> index 000000000000..759597bf0fd8 >>> - --- /dev/null >>> +++ b/arch/powerpc/include/asm/security_features.h >>> @@ -0,0 +1,92 @@ >>> +/* SPDX-License-Identifier: GPL-2.0+ */ >>> +/* >>> + * Security related feature bit definitions. >>> + * >>> + * Copyright 2018, Michael Ellerman, IBM Corporation. >>> + */ >>> + >>> +#ifndef _ASM_POWERPC_SECURITY_FEATURES_H >>> +#define _ASM_POWERPC_SECURITY_FEATURES_H >>> + >>> + >>> +extern unsigned long powerpc_security_features; >>> +extern bool rfi_flush; >>> + >>> +/* These are bit flags */ >>> +enum stf_barrier_type { >>> + STF_BARRIER_NONE = 0x1, >>> + STF_BARRIER_FALLBACK = 0x2, >>> + STF_BARRIER_EIEIO = 0x4, >>> + STF_BARRIER_SYNC_ORI = 0x8, >>> +}; >>> + >>> +void setup_stf_barrier(void); >>> +void do_stf_barrier_fixups(enum stf_barrier_type types); >>> +void setup_count_cache_flush(void); >>> + >>> +static inline void security_ftr_set(unsigned long feature) >>> +{ >>> + powerpc_security_features |= feature; >>> +} >>> + >>> +static inline void security_ftr_clear(unsigned long feature) >>> +{ >>> + powerpc_security_features &= ~feature; >>> +} >>> + >>> +static inline bool security_ftr_enabled(unsigned long feature) >>> +{ >>> + return !!(powerpc_security_features & feature); >>> +} >>> + >>> + >>> +// Features indicating support for Spectre/Meltdown mitigations >>> + >>> +// The L1-D cache can be flushed with ori r30,r30,0 >>> +#define SEC_FTR_L1D_FLUSH_ORI30 0x0000000000000001ull >>> + >>> +// The L1-D cache can be flushed with mtspr 882,r0 (aka SPRN_TRIG2) >>> +#define SEC_FTR_L1D_FLUSH_TRIG2 0x0000000000000002ull >>> + >>> +// ori r31,r31,0 acts as a speculation barrier >>> +#define SEC_FTR_SPEC_BAR_ORI31 0x0000000000000004ull >>> + >>> +// Speculation past bctr is disabled >>> +#define SEC_FTR_BCCTRL_SERIALISED 0x0000000000000008ull >>> + >>> +// Entries in L1-D are private to a SMT thread >>> +#define SEC_FTR_L1D_THREAD_PRIV 0x0000000000000010ull >>> + >>> +// Indirect branch prediction cache disabled >>> +#define SEC_FTR_COUNT_CACHE_DISABLED 0x0000000000000020ull >>> + >>> +// bcctr 2,0,0 triggers a hardware assisted count cache flush >>> +#define SEC_FTR_BCCTR_FLUSH_ASSIST 0x0000000000000800ull >>> + >>> + >>> +// Features indicating need for Spectre/Meltdown mitigations >>> + >>> +// The L1-D cache should be flushed on MSR[HV] 1->0 transition (hypervisor to guest) >>> +#define SEC_FTR_L1D_FLUSH_HV 0x0000000000000040ull >>> + >>> +// The L1-D cache should be flushed on MSR[PR] 0->1 transition (kernel to userspace) >>> +#define SEC_FTR_L1D_FLUSH_PR 0x0000000000000080ull >>> + >>> +// A speculation barrier should be used for bounds checks (Spectre variant 1) >>> +#define SEC_FTR_BNDS_CHK_SPEC_BAR 0x0000000000000100ull >>> + >>> +// Firmware configuration indicates user favours security over performance >>> +#define SEC_FTR_FAVOUR_SECURITY 0x0000000000000200ull >>> + >>> +// Software required to flush count cache on context switch >>> +#define SEC_FTR_FLUSH_COUNT_CACHE 0x0000000000000400ull >>> + >>> + >>> +// Features enabled by default >>> +#define SEC_FTR_DEFAULT \ >>> + (SEC_FTR_L1D_FLUSH_HV | \ >>> + SEC_FTR_L1D_FLUSH_PR | \ >>> + SEC_FTR_BNDS_CHK_SPEC_BAR | \ >>> + SEC_FTR_FAVOUR_SECURITY) >>> + >>> +#endif /* _ASM_POWERPC_SECURITY_FEATURES_H */ >>> diff --git a/arch/powerpc/include/asm/setup.h b/arch/powerpc/include/asm/setup.h >>> index 7916b56f2e60..d299479c770b 100644 >>> - --- a/arch/powerpc/include/asm/setup.h >>> +++ b/arch/powerpc/include/asm/setup.h >>> @@ -8,6 +8,7 @@ extern void ppc_printk_progress(char *s, unsigned short hex); >>> >>> extern unsigned int rtas_data; >>> extern unsigned long long memory_limit; >>> +extern bool init_mem_is_free; >>> extern unsigned long klimit; >>> extern void *zalloc_maybe_bootmem(size_t size, gfp_t mask); >>> >>> @@ -36,8 +37,28 @@ enum l1d_flush_type { >>> L1D_FLUSH_MTTRIG = 0x8, >>> }; >>> >>> - -void __init setup_rfi_flush(enum l1d_flush_type, bool enable); >>> +void setup_rfi_flush(enum l1d_flush_type, bool enable); >>> void do_rfi_flush_fixups(enum l1d_flush_type types); >>> +#ifdef CONFIG_PPC_BARRIER_NOSPEC >>> +void setup_barrier_nospec(void); >>> +#else >>> +static inline void setup_barrier_nospec(void) { }; >>> +#endif >>> +void do_barrier_nospec_fixups(bool enable); >>> +extern bool barrier_nospec_enabled; >>> + >>> +#ifdef CONFIG_PPC_BARRIER_NOSPEC >>> +void do_barrier_nospec_fixups_range(bool enable, void *start, void *end); >>> +#else >>> +static inline void do_barrier_nospec_fixups_range(bool enable, void *start, void *end) { }; >>> +#endif >>> + >>> +#ifdef CONFIG_PPC_FSL_BOOK3E >>> +void setup_spectre_v2(void); >>> +#else >>> +static inline void setup_spectre_v2(void) {}; >>> +#endif >>> +void do_btb_flush_fixups(void); >>> >>> #endif /* !__ASSEMBLY__ */ >>> >>> diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h >>> index 05f1389228d2..e51ce5a0e221 100644 >>> - --- a/arch/powerpc/include/asm/uaccess.h >>> +++ b/arch/powerpc/include/asm/uaccess.h >>> @@ -269,6 +269,7 @@ do { \ >>> __chk_user_ptr(ptr); \ >>> if (!is_kernel_addr((unsigned long)__gu_addr)) \ >>> might_fault(); \ >>> + barrier_nospec(); \ >>> __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \ >>> (x) = (__typeof__(*(ptr)))__gu_val; \ >>> __gu_err; \ >>> @@ -283,6 +284,7 @@ do { \ >>> __chk_user_ptr(ptr); \ >>> if (!is_kernel_addr((unsigned long)__gu_addr)) \ >>> might_fault(); \ >>> + barrier_nospec(); \ >>> __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \ >>> (x) = (__force __typeof__(*(ptr)))__gu_val; \ >>> __gu_err; \ >>> @@ -295,8 +297,10 @@ do { \ >>> unsigned long __gu_val = 0; \ >>> __typeof__(*(ptr)) __user *__gu_addr = (ptr); \ >>> might_fault(); \ >>> - - if (access_ok(VERIFY_READ, __gu_addr, (size))) \ >>> + if (access_ok(VERIFY_READ, __gu_addr, (size))) { \ >>> + barrier_nospec(); \ >>> __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \ >>> + } \ >>> (x) = (__force __typeof__(*(ptr)))__gu_val; \ >>> __gu_err; \ >>> }) >>> @@ -307,6 +311,7 @@ do { \ >>> unsigned long __gu_val; \ >>> __typeof__(*(ptr)) __user *__gu_addr = (ptr); \ >>> __chk_user_ptr(ptr); \ >>> + barrier_nospec(); \ >>> __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \ >>> (x) = (__force __typeof__(*(ptr)))__gu_val; \ >>> __gu_err; \ >>> @@ -323,8 +328,10 @@ extern unsigned long __copy_tofrom_user(void __user *to, >>> static inline unsigned long copy_from_user(void *to, >>> const void __user *from, unsigned long n) >>> { >>> - - if (likely(access_ok(VERIFY_READ, from, n))) >>> + if (likely(access_ok(VERIFY_READ, from, n))) { >>> + barrier_nospec(); >>> return __copy_tofrom_user((__force void __user *)to, from, n); >>> + } >>> memset(to, 0, n); >>> return n; >>> } >>> @@ -359,21 +366,27 @@ static inline unsigned long __copy_from_user_inatomic(void *to, >>> >>> switch (n) { >>> case 1: >>> + barrier_nospec(); >>> __get_user_size(*(u8 *)to, from, 1, ret); >>> break; >>> case 2: >>> + barrier_nospec(); >>> __get_user_size(*(u16 *)to, from, 2, ret); >>> break; >>> case 4: >>> + barrier_nospec(); >>> __get_user_size(*(u32 *)to, from, 4, ret); >>> break; >>> case 8: >>> + barrier_nospec(); >>> __get_user_size(*(u64 *)to, from, 8, ret); >>> break; >>> } >>> if (ret == 0) >>> return 0; >>> } >>> + >>> + barrier_nospec(); >>> return __copy_tofrom_user((__force void __user *)to, from, n); >>> } >>> >>> @@ -400,6 +413,7 @@ static inline unsigned long __copy_to_user_inatomic(void __user *to, >>> if (ret == 0) >>> return 0; >>> } >>> + >>> return __copy_tofrom_user(to, (__force const void __user *)from, n); >>> } >>> >>> diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile >>> index ba336930d448..22ed3c32fca8 100644 >>> - --- a/arch/powerpc/kernel/Makefile >>> +++ b/arch/powerpc/kernel/Makefile >>> @@ -44,6 +44,7 @@ obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_power.o >>> obj-$(CONFIG_PPC_BOOK3S_64) += mce.o mce_power.o >>> obj64-$(CONFIG_RELOCATABLE) += reloc_64.o >>> obj-$(CONFIG_PPC_BOOK3E_64) += exceptions-64e.o idle_book3e.o >>> +obj-$(CONFIG_PPC_BARRIER_NOSPEC) += security.o >>> obj-$(CONFIG_PPC64) += vdso64/ >>> obj-$(CONFIG_ALTIVEC) += vecemu.o >>> obj-$(CONFIG_PPC_970_NAP) += idle_power4.o >>> diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c >>> index d92705e3a0c1..de3c29c51503 100644 >>> - --- a/arch/powerpc/kernel/asm-offsets.c >>> +++ b/arch/powerpc/kernel/asm-offsets.c >>> @@ -245,8 +245,7 @@ int main(void) >>> DEFINE(PACA_IN_MCE, offsetof(struct paca_struct, in_mce)); >>> DEFINE(PACA_RFI_FLUSH_FALLBACK_AREA, offsetof(struct paca_struct, rfi_flush_fallback_area)); >>> DEFINE(PACA_EXRFI, offsetof(struct paca_struct, exrfi)); >>> - - DEFINE(PACA_L1D_FLUSH_CONGRUENCE, offsetof(struct paca_struct, l1d_flush_congruence)); >>> - - DEFINE(PACA_L1D_FLUSH_SETS, offsetof(struct paca_struct, l1d_flush_sets)); >>> + DEFINE(PACA_L1D_FLUSH_SIZE, offsetof(struct paca_struct, l1d_flush_size)); >>> #endif >>> DEFINE(PACAHWCPUID, offsetof(struct paca_struct, hw_cpu_id)); >>> DEFINE(PACAKEXECSTATE, offsetof(struct paca_struct, kexec_state)); >>> diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S >>> index 59be96917369..6d36a4fb4acf 100644 >>> - --- a/arch/powerpc/kernel/entry_64.S >>> +++ b/arch/powerpc/kernel/entry_64.S >>> @@ -25,6 +25,7 @@ >>> #include <asm/page.h> >>> #include <asm/mmu.h> >>> #include <asm/thread_info.h> >>> +#include <asm/code-patching-asm.h> >>> #include <asm/ppc_asm.h> >>> #include <asm/asm-offsets.h> >>> #include <asm/cputable.h> >>> @@ -36,6 +37,7 @@ >>> #include <asm/hw_irq.h> >>> #include <asm/context_tracking.h> >>> #include <asm/tm.h> >>> +#include <asm/barrier.h> >>> #ifdef CONFIG_PPC_BOOK3S >>> #include <asm/exception-64s.h> >>> #else >>> @@ -75,6 +77,11 @@ END_FTR_SECTION_IFSET(CPU_FTR_TM) >>> std r0,GPR0(r1) >>> std r10,GPR1(r1) >>> beq 2f /* if from kernel mode */ >>> +#ifdef CONFIG_PPC_FSL_BOOK3E >>> +START_BTB_FLUSH_SECTION >>> + BTB_FLUSH(r10) >>> +END_BTB_FLUSH_SECTION >>> +#endif >>> ACCOUNT_CPU_USER_ENTRY(r10, r11) >>> 2: std r2,GPR2(r1) >>> std r3,GPR3(r1) >>> @@ -177,6 +184,15 @@ system_call: /* label this so stack traces look sane */ >>> clrldi r8,r8,32 >>> 15: >>> slwi r0,r0,4 >>> + >>> + barrier_nospec_asm >>> + /* >>> + * Prevent the load of the handler below (based on the user-passed >>> + * system call number) being speculatively executed until the test >>> + * against NR_syscalls and branch to .Lsyscall_enosys above has >>> + * committed. >>> + */ >>> + >>> ldx r12,r11,r0 /* Fetch system call handler [ptr] */ >>> mtctr r12 >>> bctrl /* Call handler */ >>> @@ -440,6 +456,57 @@ _GLOBAL(ret_from_kernel_thread) >>> li r3,0 >>> b .Lsyscall_exit >>> >>> +#ifdef CONFIG_PPC_BOOK3S_64 >>> + >>> +#define FLUSH_COUNT_CACHE \ >>> +1: nop; \ >>> + patch_site 1b, patch__call_flush_count_cache >>> + >>> + >>> +#define BCCTR_FLUSH .long 0x4c400420 >>> + >>> +.macro nops number >>> + .rept \number >>> + nop >>> + .endr >>> +.endm >>> + >>> +.balign 32 >>> +.global flush_count_cache >>> +flush_count_cache: >>> + /* Save LR into r9 */ >>> + mflr r9 >>> + >>> + .rept 64 >>> + bl .+4 >>> + .endr >>> + b 1f >>> + nops 6 >>> + >>> + .balign 32 >>> + /* Restore LR */ >>> +1: mtlr r9 >>> + li r9,0x7fff >>> + mtctr r9 >>> + >>> + BCCTR_FLUSH >>> + >>> +2: nop >>> + patch_site 2b patch__flush_count_cache_return >>> + >>> + nops 3 >>> + >>> + .rept 278 >>> + .balign 32 >>> + BCCTR_FLUSH >>> + nops 7 >>> + .endr >>> + >>> + blr >>> +#else >>> +#define FLUSH_COUNT_CACHE >>> +#endif /* CONFIG_PPC_BOOK3S_64 */ >>> + >>> /* >>> * This routine switches between two different tasks. The process >>> * state of one is saved on its kernel stack. Then the state >>> @@ -503,6 +570,8 @@ BEGIN_FTR_SECTION >>> END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) >>> #endif >>> >>> + FLUSH_COUNT_CACHE >>> + >>> #ifdef CONFIG_SMP >>> /* We need a sync somewhere here to make sure that if the >>> * previous task gets rescheduled on another CPU, it sees all >>> diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S >>> index 5cc93f0b52ca..48ec841ea1bf 100644 >>> - --- a/arch/powerpc/kernel/exceptions-64e.S >>> +++ b/arch/powerpc/kernel/exceptions-64e.S >>> @@ -295,7 +295,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_EMB_HV) >>> andi. r10,r11,MSR_PR; /* save stack pointer */ \ >>> beq 1f; /* branch around if supervisor */ \ >>> ld r1,PACAKSAVE(r13); /* get kernel stack coming from usr */\ >>> - -1: cmpdi cr1,r1,0; /* check if SP makes sense */ \ >>> +1: type##_BTB_FLUSH \ >>> + cmpdi cr1,r1,0; /* check if SP makes sense */ \ >>> bge- cr1,exc_##n##_bad_stack;/* bad stack (TODO: out of line) */ \ >>> mfspr r10,SPRN_##type##_SRR0; /* read SRR0 before touching stack */ >>> >>> @@ -327,6 +328,30 @@ END_FTR_SECTION_IFSET(CPU_FTR_EMB_HV) >>> #define SPRN_MC_SRR0 SPRN_MCSRR0 >>> #define SPRN_MC_SRR1 SPRN_MCSRR1 >>> >>> +#ifdef CONFIG_PPC_FSL_BOOK3E >>> +#define GEN_BTB_FLUSH \ >>> + START_BTB_FLUSH_SECTION \ >>> + beq 1f; \ >>> + BTB_FLUSH(r10) \ >>> + 1: \ >>> + END_BTB_FLUSH_SECTION >>> + >>> +#define CRIT_BTB_FLUSH \ >>> + START_BTB_FLUSH_SECTION \ >>> + BTB_FLUSH(r10) \ >>> + END_BTB_FLUSH_SECTION >>> + >>> +#define DBG_BTB_FLUSH CRIT_BTB_FLUSH >>> +#define MC_BTB_FLUSH CRIT_BTB_FLUSH >>> +#define GDBELL_BTB_FLUSH GEN_BTB_FLUSH >>> +#else >>> +#define GEN_BTB_FLUSH >>> +#define CRIT_BTB_FLUSH >>> +#define DBG_BTB_FLUSH >>> +#define MC_BTB_FLUSH >>> +#define GDBELL_BTB_FLUSH >>> +#endif >>> + >>> #define NORMAL_EXCEPTION_PROLOG(n, intnum, addition) \ >>> EXCEPTION_PROLOG(n, intnum, GEN, addition##_GEN(n)) >>> >>> diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S >>> index 938a30fef031..10e7cec9553d 100644 >>> - --- a/arch/powerpc/kernel/exceptions-64s.S >>> +++ b/arch/powerpc/kernel/exceptions-64s.S >>> @@ -36,6 +36,7 @@ BEGIN_FTR_SECTION \ >>> END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) \ >>> mr r9,r13 ; \ >>> GET_PACA(r13) ; \ >>> + INTERRUPT_TO_KERNEL ; \ >>> mfspr r11,SPRN_SRR0 ; \ >>> 0: >>> >>> @@ -292,7 +293,9 @@ ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE) >>> . = 0x900 >>> .globl decrementer_pSeries >>> decrementer_pSeries: >>> - - _MASKABLE_EXCEPTION_PSERIES(0x900, decrementer, EXC_STD, SOFTEN_TEST_PR) >>> + SET_SCRATCH0(r13) >>> + EXCEPTION_PROLOG_0(PACA_EXGEN) >>> + b decrementer_ool >>> >>> STD_EXCEPTION_HV(0x980, 0x982, hdecrementer) >>> >>> @@ -319,6 +322,7 @@ ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE) >>> OPT_GET_SPR(r9, SPRN_PPR, CPU_FTR_HAS_PPR); >>> HMT_MEDIUM; >>> std r10,PACA_EXGEN+EX_R10(r13) >>> + INTERRUPT_TO_KERNEL >>> OPT_SAVE_REG_TO_PACA(PACA_EXGEN+EX_PPR, r9, CPU_FTR_HAS_PPR); >>> mfcr r9 >>> KVMTEST(0xc00) >>> @@ -607,6 +611,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_CFAR) >>> >>> .align 7 >>> /* moved from 0xe00 */ >>> + MASKABLE_EXCEPTION_OOL(0x900, decrementer) >>> STD_EXCEPTION_HV_OOL(0xe02, h_data_storage) >>> KVM_HANDLER_SKIP(PACA_EXGEN, EXC_HV, 0xe02) >>> STD_EXCEPTION_HV_OOL(0xe22, h_instr_storage) >>> @@ -1564,6 +1569,21 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX) >>> blr >>> #endif >>> >>> + .balign 16 >>> + .globl stf_barrier_fallback >>> +stf_barrier_fallback: >>> + std r9,PACA_EXRFI+EX_R9(r13) >>> + std r10,PACA_EXRFI+EX_R10(r13) >>> + sync >>> + ld r9,PACA_EXRFI+EX_R9(r13) >>> + ld r10,PACA_EXRFI+EX_R10(r13) >>> + ori 31,31,0 >>> + .rept 14 >>> + b 1f >>> +1: >>> + .endr >>> + blr >>> + >>> .globl rfi_flush_fallback >>> rfi_flush_fallback: >>> SET_SCRATCH0(r13); >>> @@ -1571,39 +1591,37 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX) >>> std r9,PACA_EXRFI+EX_R9(r13) >>> std r10,PACA_EXRFI+EX_R10(r13) >>> std r11,PACA_EXRFI+EX_R11(r13) >>> - - std r12,PACA_EXRFI+EX_R12(r13) >>> - - std r8,PACA_EXRFI+EX_R13(r13) >>> mfctr r9 >>> ld r10,PACA_RFI_FLUSH_FALLBACK_AREA(r13) >>> - - ld r11,PACA_L1D_FLUSH_SETS(r13) >>> - - ld r12,PACA_L1D_FLUSH_CONGRUENCE(r13) >>> - - /* >>> - - * The load adresses are at staggered offsets within cachelines, >>> - - * which suits some pipelines better (on others it should not >>> - - * hurt). >>> - - */ >>> - - addi r12,r12,8 >>> + ld r11,PACA_L1D_FLUSH_SIZE(r13) >>> + srdi r11,r11,(7 + 3) /* 128 byte lines, unrolled 8x */ >>> mtctr r11 >>> DCBT_STOP_ALL_STREAM_IDS(r11) /* Stop prefetch streams */ >>> >>> /* order ld/st prior to dcbt stop all streams with flushing */ >>> sync >>> - -1: li r8,0 >>> - - .rept 8 /* 8-way set associative */ >>> - - ldx r11,r10,r8 >>> - - add r8,r8,r12 >>> - - xor r11,r11,r11 // Ensure r11 is 0 even if fallback area is not >>> - - add r8,r8,r11 // Add 0, this creates a dependency on the ldx >>> - - .endr >>> - - addi r10,r10,128 /* 128 byte cache line */ >>> + >>> + /* >>> + * The load adresses are at staggered offsets within cachelines, >>> + * which suits some pipelines better (on others it should not >>> + * hurt). >>> + */ >>> +1: >>> + ld r11,(0x80 + 8)*0(r10) >>> + ld r11,(0x80 + 8)*1(r10) >>> + ld r11,(0x80 + 8)*2(r10) >>> + ld r11,(0x80 + 8)*3(r10) >>> + ld r11,(0x80 + 8)*4(r10) >>> + ld r11,(0x80 + 8)*5(r10) >>> + ld r11,(0x80 + 8)*6(r10) >>> + ld r11,(0x80 + 8)*7(r10) >>> + addi r10,r10,0x80*8 >>> bdnz 1b >>> >>> mtctr r9 >>> ld r9,PACA_EXRFI+EX_R9(r13) >>> ld r10,PACA_EXRFI+EX_R10(r13) >>> ld r11,PACA_EXRFI+EX_R11(r13) >>> - - ld r12,PACA_EXRFI+EX_R12(r13) >>> - - ld r8,PACA_EXRFI+EX_R13(r13) >>> GET_SCRATCH0(r13); >>> rfid >>> >>> @@ -1614,39 +1632,37 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX) >>> std r9,PACA_EXRFI+EX_R9(r13) >>> std r10,PACA_EXRFI+EX_R10(r13) >>> std r11,PACA_EXRFI+EX_R11(r13) >>> - - std r12,PACA_EXRFI+EX_R12(r13) >>> - - std r8,PACA_EXRFI+EX_R13(r13) >>> mfctr r9 >>> ld r10,PACA_RFI_FLUSH_FALLBACK_AREA(r13) >>> - - ld r11,PACA_L1D_FLUSH_SETS(r13) >>> - - ld r12,PACA_L1D_FLUSH_CONGRUENCE(r13) >>> - - /* >>> - - * The load adresses are at staggered offsets within cachelines, >>> - - * which suits some pipelines better (on others it should not >>> - - * hurt). >>> - - */ >>> - - addi r12,r12,8 >>> + ld r11,PACA_L1D_FLUSH_SIZE(r13) >>> + srdi r11,r11,(7 + 3) /* 128 byte lines, unrolled 8x */ >>> mtctr r11 >>> DCBT_STOP_ALL_STREAM_IDS(r11) /* Stop prefetch streams */ >>> >>> /* order ld/st prior to dcbt stop all streams with flushing */ >>> sync >>> - -1: li r8,0 >>> - - .rept 8 /* 8-way set associative */ >>> - - ldx r11,r10,r8 >>> - - add r8,r8,r12 >>> - - xor r11,r11,r11 // Ensure r11 is 0 even if fallback area is not >>> - - add r8,r8,r11 // Add 0, this creates a dependency on the ldx >>> - - .endr >>> - - addi r10,r10,128 /* 128 byte cache line */ >>> + >>> + /* >>> + * The load adresses are at staggered offsets within cachelines, >>> + * which suits some pipelines better (on others it should not >>> + * hurt). >>> + */ >>> +1: >>> + ld r11,(0x80 + 8)*0(r10) >>> + ld r11,(0x80 + 8)*1(r10) >>> + ld r11,(0x80 + 8)*2(r10) >>> + ld r11,(0x80 + 8)*3(r10) >>> + ld r11,(0x80 + 8)*4(r10) >>> + ld r11,(0x80 + 8)*5(r10) >>> + ld r11,(0x80 + 8)*6(r10) >>> + ld r11,(0x80 + 8)*7(r10) >>> + addi r10,r10,0x80*8 >>> bdnz 1b >>> >>> mtctr r9 >>> ld r9,PACA_EXRFI+EX_R9(r13) >>> ld r10,PACA_EXRFI+EX_R10(r13) >>> ld r11,PACA_EXRFI+EX_R11(r13) >>> - - ld r12,PACA_EXRFI+EX_R12(r13) >>> - - ld r8,PACA_EXRFI+EX_R13(r13) >>> GET_SCRATCH0(r13); >>> hrfid >>> >>> diff --git a/arch/powerpc/kernel/module.c b/arch/powerpc/kernel/module.c >>> index 9547381b631a..ff009be97a42 100644 >>> - --- a/arch/powerpc/kernel/module.c >>> +++ b/arch/powerpc/kernel/module.c >>> @@ -67,7 +67,15 @@ int module_finalize(const Elf_Ehdr *hdr, >>> do_feature_fixups(powerpc_firmware_features, >>> (void *)sect->sh_addr, >>> (void *)sect->sh_addr + sect->sh_size); >>> - -#endif >>> +#endif /* CONFIG_PPC64 */ >>> + >>> +#ifdef CONFIG_PPC_BARRIER_NOSPEC >>> + sect = find_section(hdr, sechdrs, "__spec_barrier_fixup"); >>> + if (sect != NULL) >>> + do_barrier_nospec_fixups_range(barrier_nospec_enabled, >>> + (void *)sect->sh_addr, >>> + (void *)sect->sh_addr + sect->sh_size); >>> +#endif /* CONFIG_PPC_BARRIER_NOSPEC */ >>> >>> sect = find_section(hdr, sechdrs, "__lwsync_fixup"); >>> if (sect != NULL) >>> diff --git a/arch/powerpc/kernel/security.c b/arch/powerpc/kernel/security.c >>> new file mode 100644 >>> index 000000000000..58f0602a92b9 >>> - --- /dev/null >>> +++ b/arch/powerpc/kernel/security.c >>> @@ -0,0 +1,433 @@ >>> +// SPDX-License-Identifier: GPL-2.0+ >>> +// >>> +// Security related flags and so on. >>> +// >>> +// Copyright 2018, Michael Ellerman, IBM Corporation. >>> + >>> +#include <linux/kernel.h> >>> +#include <linux/debugfs.h> >>> +#include <linux/device.h> >>> +#include <linux/seq_buf.h> >>> + >>> +#include <asm/debug.h> >>> +#include <asm/asm-prototypes.h> >>> +#include <asm/code-patching.h> >>> +#include <asm/security_features.h> >>> +#include <asm/setup.h> >>> + >>> + >>> +unsigned long powerpc_security_features __read_mostly = SEC_FTR_DEFAULT; >>> + >>> +enum count_cache_flush_type { >>> + COUNT_CACHE_FLUSH_NONE = 0x1, >>> + COUNT_CACHE_FLUSH_SW = 0x2, >>> + COUNT_CACHE_FLUSH_HW = 0x4, >>> +}; >>> +static enum count_cache_flush_type count_cache_flush_type = COUNT_CACHE_FLUSH_NONE; >>> + >>> +bool barrier_nospec_enabled; >>> +static bool no_nospec; >>> +static bool btb_flush_enabled; >>> +#ifdef CONFIG_PPC_FSL_BOOK3E >>> +static bool no_spectrev2; >>> +#endif >>> + >>> +static void enable_barrier_nospec(bool enable) >>> +{ >>> + barrier_nospec_enabled = enable; >>> + do_barrier_nospec_fixups(enable); >>> +} >>> + >>> +void setup_barrier_nospec(void) >>> +{ >>> + bool enable; >>> + >>> + /* >>> + * It would make sense to check SEC_FTR_SPEC_BAR_ORI31 below as well. >>> + * But there's a good reason not to. The two flags we check below are >>> + * both are enabled by default in the kernel, so if the hcall is not >>> + * functional they will be enabled. >>> + * On a system where the host firmware has been updated (so the ori >>> + * functions as a barrier), but on which the hypervisor (KVM/Qemu) has >>> + * not been updated, we would like to enable the barrier. Dropping the >>> + * check for SEC_FTR_SPEC_BAR_ORI31 achieves that. The only downside is >>> + * we potentially enable the barrier on systems where the host firmware >>> + * is not updated, but that's harmless as it's a no-op. >>> + */ >>> + enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) && >>> + security_ftr_enabled(SEC_FTR_BNDS_CHK_SPEC_BAR); >>> + >>> + if (!no_nospec) >>> + enable_barrier_nospec(enable); >>> +} >>> + >>> +static int __init handle_nospectre_v1(char *p) >>> +{ >>> + no_nospec = true; >>> + >>> + return 0; >>> +} >>> +early_param("nospectre_v1", handle_nospectre_v1); >>> + >>> +#ifdef CONFIG_DEBUG_FS >>> +static int barrier_nospec_set(void *data, u64 val) >>> +{ >>> + switch (val) { >>> + case 0: >>> + case 1: >>> + break; >>> + default: >>> + return -EINVAL; >>> + } >>> + >>> + if (!!val == !!barrier_nospec_enabled) >>> + return 0; >>> + >>> + enable_barrier_nospec(!!val); >>> + >>> + return 0; >>> +} >>> + >>> +static int barrier_nospec_get(void *data, u64 *val) >>> +{ >>> + *val = barrier_nospec_enabled ? 1 : 0; >>> + return 0; >>> +} >>> + >>> +DEFINE_SIMPLE_ATTRIBUTE(fops_barrier_nospec, >>> + barrier_nospec_get, barrier_nospec_set, "%llu\n"); >>> + >>> +static __init int barrier_nospec_debugfs_init(void) >>> +{ >>> + debugfs_create_file("barrier_nospec", 0600, powerpc_debugfs_root, NULL, >>> + &fops_barrier_nospec); >>> + return 0; >>> +} >>> +device_initcall(barrier_nospec_debugfs_init); >>> +#endif /* CONFIG_DEBUG_FS */ >>> + >>> +#ifdef CONFIG_PPC_FSL_BOOK3E >>> +static int __init handle_nospectre_v2(char *p) >>> +{ >>> + no_spectrev2 = true; >>> + >>> + return 0; >>> +} >>> +early_param("nospectre_v2", handle_nospectre_v2); >>> +void setup_spectre_v2(void) >>> +{ >>> + if (no_spectrev2) >>> + do_btb_flush_fixups(); >>> + else >>> + btb_flush_enabled = true; >>> +} >>> +#endif /* CONFIG_PPC_FSL_BOOK3E */ >>> + >>> +#ifdef CONFIG_PPC_BOOK3S_64 >>> +ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, char *buf) >>> +{ >>> + bool thread_priv; >>> + >>> + thread_priv = security_ftr_enabled(SEC_FTR_L1D_THREAD_PRIV); >>> + >>> + if (rfi_flush || thread_priv) { >>> + struct seq_buf s; >>> + seq_buf_init(&s, buf, PAGE_SIZE - 1); >>> + >>> + seq_buf_printf(&s, "Mitigation: "); >>> + >>> + if (rfi_flush) >>> + seq_buf_printf(&s, "RFI Flush"); >>> + >>> + if (rfi_flush && thread_priv) >>> + seq_buf_printf(&s, ", "); >>> + >>> + if (thread_priv) >>> + seq_buf_printf(&s, "L1D private per thread"); >>> + >>> + seq_buf_printf(&s, "\n"); >>> + >>> + return s.len; >>> + } >>> + >>> + if (!security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) && >>> + !security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR)) >>> + return sprintf(buf, "Not affected\n"); >>> + >>> + return sprintf(buf, "Vulnerable\n"); >>> +} >>> +#endif >>> + >>> +ssize_t cpu_show_spectre_v1(struct device *dev, struct device_attribute *attr, char *buf) >>> +{ >>> + struct seq_buf s; >>> + >>> + seq_buf_init(&s, buf, PAGE_SIZE - 1); >>> + >>> + if (security_ftr_enabled(SEC_FTR_BNDS_CHK_SPEC_BAR)) { >>> + if (barrier_nospec_enabled) >>> + seq_buf_printf(&s, "Mitigation: __user pointer sanitization"); >>> + else >>> + seq_buf_printf(&s, "Vulnerable"); >>> + >>> + if (security_ftr_enabled(SEC_FTR_SPEC_BAR_ORI31)) >>> + seq_buf_printf(&s, ", ori31 speculation barrier enabled"); >>> + >>> + seq_buf_printf(&s, "\n"); >>> + } else >>> + seq_buf_printf(&s, "Not affected\n"); >>> + >>> + return s.len; >>> +} >>> + >>> +ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr, char *buf) >>> +{ >>> + struct seq_buf s; >>> + bool bcs, ccd; >>> + >>> + seq_buf_init(&s, buf, PAGE_SIZE - 1); >>> + >>> + bcs = security_ftr_enabled(SEC_FTR_BCCTRL_SERIALISED); >>> + ccd = security_ftr_enabled(SEC_FTR_COUNT_CACHE_DISABLED); >>> + >>> + if (bcs || ccd) { >>> + seq_buf_printf(&s, "Mitigation: "); >>> + >>> + if (bcs) >>> + seq_buf_printf(&s, "Indirect branch serialisation (kernel only)"); >>> + >>> + if (bcs && ccd) >>> + seq_buf_printf(&s, ", "); >>> + >>> + if (ccd) >>> + seq_buf_printf(&s, "Indirect branch cache disabled"); >>> + } else if (count_cache_flush_type != COUNT_CACHE_FLUSH_NONE) { >>> + seq_buf_printf(&s, "Mitigation: Software count cache flush"); >>> + >>> + if (count_cache_flush_type == COUNT_CACHE_FLUSH_HW) >>> + seq_buf_printf(&s, " (hardware accelerated)"); >>> + } else if (btb_flush_enabled) { >>> + seq_buf_printf(&s, "Mitigation: Branch predictor state flush"); >>> + } else { >>> + seq_buf_printf(&s, "Vulnerable"); >>> + } >>> + >>> + seq_buf_printf(&s, "\n"); >>> + >>> + return s.len; >>> +} >>> + >>> +#ifdef CONFIG_PPC_BOOK3S_64 >>> +/* >>> + * Store-forwarding barrier support. >>> + */ >>> + >>> +static enum stf_barrier_type stf_enabled_flush_types; >>> +static bool no_stf_barrier; >>> +bool stf_barrier; >>> + >>> +static int __init handle_no_stf_barrier(char *p) >>> +{ >>> + pr_info("stf-barrier: disabled on command line."); >>> + no_stf_barrier = true; >>> + return 0; >>> +} >>> + >>> +early_param("no_stf_barrier", handle_no_stf_barrier); >>> + >>> +/* This is the generic flag used by other architectures */ >>> +static int __init handle_ssbd(char *p) >>> +{ >>> + if (!p || strncmp(p, "auto", 5) == 0 || strncmp(p, "on", 2) == 0 ) { >>> + /* Until firmware tells us, we have the barrier with auto */ >>> + return 0; >>> + } else if (strncmp(p, "off", 3) == 0) { >>> + handle_no_stf_barrier(NULL); >>> + return 0; >>> + } else >>> + return 1; >>> + >>> + return 0; >>> +} >>> +early_param("spec_store_bypass_disable", handle_ssbd); >>> + >>> +/* This is the generic flag used by other architectures */ >>> +static int __init handle_no_ssbd(char *p) >>> +{ >>> + handle_no_stf_barrier(NULL); >>> + return 0; >>> +} >>> +early_param("nospec_store_bypass_disable", handle_no_ssbd); >>> + >>> +static void stf_barrier_enable(bool enable) >>> +{ >>> + if (enable) >>> + do_stf_barrier_fixups(stf_enabled_flush_types); >>> + else >>> + do_stf_barrier_fixups(STF_BARRIER_NONE); >>> + >>> + stf_barrier = enable; >>> +} >>> + >>> +void setup_stf_barrier(void) >>> +{ >>> + enum stf_barrier_type type; >>> + bool enable, hv; >>> + >>> + hv = cpu_has_feature(CPU_FTR_HVMODE); >>> + >>> + /* Default to fallback in case fw-features are not available */ >>> + if (cpu_has_feature(CPU_FTR_ARCH_207S)) >>> + type = STF_BARRIER_SYNC_ORI; >>> + else if (cpu_has_feature(CPU_FTR_ARCH_206)) >>> + type = STF_BARRIER_FALLBACK; >>> + else >>> + type = STF_BARRIER_NONE; >>> + >>> + enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) && >>> + (security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR) || >>> + (security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) && hv)); >>> + >>> + if (type == STF_BARRIER_FALLBACK) { >>> + pr_info("stf-barrier: fallback barrier available\n"); >>> + } else if (type == STF_BARRIER_SYNC_ORI) { >>> + pr_info("stf-barrier: hwsync barrier available\n"); >>> + } else if (type == STF_BARRIER_EIEIO) { >>> + pr_info("stf-barrier: eieio barrier available\n"); >>> + } >>> + >>> + stf_enabled_flush_types = type; >>> + >>> + if (!no_stf_barrier) >>> + stf_barrier_enable(enable); >>> +} >>> + >>> +ssize_t cpu_show_spec_store_bypass(struct device *dev, struct device_attribute *attr, char *buf) >>> +{ >>> + if (stf_barrier && stf_enabled_flush_types != STF_BARRIER_NONE) { >>> + const char *type; >>> + switch (stf_enabled_flush_types) { >>> + case STF_BARRIER_EIEIO: >>> + type = "eieio"; >>> + break; >>> + case STF_BARRIER_SYNC_ORI: >>> + type = "hwsync"; >>> + break; >>> + case STF_BARRIER_FALLBACK: >>> + type = "fallback"; >>> + break; >>> + default: >>> + type = "unknown"; >>> + } >>> + return sprintf(buf, "Mitigation: Kernel entry/exit barrier (%s)\n", type); >>> + } >>> + >>> + if (!security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) && >>> + !security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR)) >>> + return sprintf(buf, "Not affected\n"); >>> + >>> + return sprintf(buf, "Vulnerable\n"); >>> +} >>> + >>> +#ifdef CONFIG_DEBUG_FS >>> +static int stf_barrier_set(void *data, u64 val) >>> +{ >>> + bool enable; >>> + >>> + if (val == 1) >>> + enable = true; >>> + else if (val == 0) >>> + enable = false; >>> + else >>> + return -EINVAL; >>> + >>> + /* Only do anything if we're changing state */ >>> + if (enable != stf_barrier) >>> + stf_barrier_enable(enable); >>> + >>> + return 0; >>> +} >>> + >>> +static int stf_barrier_get(void *data, u64 *val) >>> +{ >>> + *val = stf_barrier ? 1 : 0; >>> + return 0; >>> +} >>> + >>> +DEFINE_SIMPLE_ATTRIBUTE(fops_stf_barrier, stf_barrier_get, stf_barrier_set, "%llu\n"); >>> + >>> +static __init int stf_barrier_debugfs_init(void) >>> +{ >>> + debugfs_create_file("stf_barrier", 0600, powerpc_debugfs_root, NULL, &fops_stf_barrier); >>> + return 0; >>> +} >>> +device_initcall(stf_barrier_debugfs_init); >>> +#endif /* CONFIG_DEBUG_FS */ >>> + >>> +static void toggle_count_cache_flush(bool enable) >>> +{ >>> + if (!enable || !security_ftr_enabled(SEC_FTR_FLUSH_COUNT_CACHE)) { >>> + patch_instruction_site(&patch__call_flush_count_cache, PPC_INST_NOP); >>> + count_cache_flush_type = COUNT_CACHE_FLUSH_NONE; >>> + pr_info("count-cache-flush: software flush disabled.\n"); >>> + return; >>> + } >>> + >>> + patch_branch_site(&patch__call_flush_count_cache, >>> + (u64)&flush_count_cache, BRANCH_SET_LINK); >>> + >>> + if (!security_ftr_enabled(SEC_FTR_BCCTR_FLUSH_ASSIST)) { >>> + count_cache_flush_type = COUNT_CACHE_FLUSH_SW; >>> + pr_info("count-cache-flush: full software flush sequence enabled.\n"); >>> + return; >>> + } >>> + >>> + patch_instruction_site(&patch__flush_count_cache_return, PPC_INST_BLR); >>> + count_cache_flush_type = COUNT_CACHE_FLUSH_HW; >>> + pr_info("count-cache-flush: hardware assisted flush sequence enabled\n"); >>> +} >>> + >>> +void setup_count_cache_flush(void) >>> +{ >>> + toggle_count_cache_flush(true); >>> +} >>> + >>> +#ifdef CONFIG_DEBUG_FS >>> +static int count_cache_flush_set(void *data, u64 val) >>> +{ >>> + bool enable; >>> + >>> + if (val == 1) >>> + enable = true; >>> + else if (val == 0) >>> + enable = false; >>> + else >>> + return -EINVAL; >>> + >>> + toggle_count_cache_flush(enable); >>> + >>> + return 0; >>> +} >>> + >>> +static int count_cache_flush_get(void *data, u64 *val) >>> +{ >>> + if (count_cache_flush_type == COUNT_CACHE_FLUSH_NONE) >>> + *val = 0; >>> + else >>> + *val = 1; >>> + >>> + return 0; >>> +} >>> + >>> +DEFINE_SIMPLE_ATTRIBUTE(fops_count_cache_flush, count_cache_flush_get, >>> + count_cache_flush_set, "%llu\n"); >>> + >>> +static __init int count_cache_flush_debugfs_init(void) >>> +{ >>> + debugfs_create_file("count_cache_flush", 0600, powerpc_debugfs_root, >>> + NULL, &fops_count_cache_flush); >>> + return 0; >>> +} >>> +device_initcall(count_cache_flush_debugfs_init); >>> +#endif /* CONFIG_DEBUG_FS */ >>> +#endif /* CONFIG_PPC_BOOK3S_64 */ >>> diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c >>> index ad8c9db61237..5a9f035bcd6b 100644 >>> - --- a/arch/powerpc/kernel/setup_32.c >>> +++ b/arch/powerpc/kernel/setup_32.c >>> @@ -322,6 +322,8 @@ void __init setup_arch(char **cmdline_p) >>> ppc_md.setup_arch(); >>> if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab); >>> >>> + setup_barrier_nospec(); >>> + >>> paging_init(); >>> >>> /* Initialize the MMU context management stuff */ >>> diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c >>> index 9eb469bed22b..6bb731ababc6 100644 >>> - --- a/arch/powerpc/kernel/setup_64.c >>> +++ b/arch/powerpc/kernel/setup_64.c >>> @@ -736,6 +736,8 @@ void __init setup_arch(char **cmdline_p) >>> if (ppc_md.setup_arch) >>> ppc_md.setup_arch(); >>> >>> + setup_barrier_nospec(); >>> + >>> paging_init(); >>> >>> /* Initialize the MMU context management stuff */ >>> @@ -873,9 +875,6 @@ static void do_nothing(void *unused) >>> >>> void rfi_flush_enable(bool enable) >>> { >>> - - if (rfi_flush == enable) >>> - - return; >>> - - >>> if (enable) { >>> do_rfi_flush_fixups(enabled_flush_types); >>> on_each_cpu(do_nothing, NULL, 1); >>> @@ -885,11 +884,15 @@ void rfi_flush_enable(bool enable) >>> rfi_flush = enable; >>> } >>> >>> - -static void init_fallback_flush(void) >>> +static void __ref init_fallback_flush(void) >>> { >>> u64 l1d_size, limit; >>> int cpu; >>> >>> + /* Only allocate the fallback flush area once (at boot time). */ >>> + if (l1d_flush_fallback_area) >>> + return; >>> + >>> l1d_size = ppc64_caches.dsize; >>> limit = min(safe_stack_limit(), ppc64_rma_size); >>> >>> @@ -902,34 +905,23 @@ static void init_fallback_flush(void) >>> memset(l1d_flush_fallback_area, 0, l1d_size * 2); >>> >>> for_each_possible_cpu(cpu) { >>> - - /* >>> - - * The fallback flush is currently coded for 8-way >>> - - * associativity. Different associativity is possible, but it >>> - - * will be treated as 8-way and may not evict the lines as >>> - - * effectively. >>> - - * >>> - - * 128 byte lines are mandatory. >>> - - */ >>> - - u64 c = l1d_size / 8; >>> - - >>> paca[cpu].rfi_flush_fallback_area = l1d_flush_fallback_area; >>> - - paca[cpu].l1d_flush_congruence = c; >>> - - paca[cpu].l1d_flush_sets = c / 128; >>> + paca[cpu].l1d_flush_size = l1d_size; >>> } >>> } >>> >>> - -void __init setup_rfi_flush(enum l1d_flush_type types, bool enable) >>> +void setup_rfi_flush(enum l1d_flush_type types, bool enable) >>> { >>> if (types & L1D_FLUSH_FALLBACK) { >>> - - pr_info("rfi-flush: Using fallback displacement flush\n"); >>> + pr_info("rfi-flush: fallback displacement flush available\n"); >>> init_fallback_flush(); >>> } >>> >>> if (types & L1D_FLUSH_ORI) >>> - - pr_info("rfi-flush: Using ori type flush\n"); >>> + pr_info("rfi-flush: ori type flush available\n"); >>> >>> if (types & L1D_FLUSH_MTTRIG) >>> - - pr_info("rfi-flush: Using mttrig type flush\n"); >>> + pr_info("rfi-flush: mttrig type flush available\n"); >>> >>> enabled_flush_types = types; >>> >>> @@ -940,13 +932,19 @@ void __init setup_rfi_flush(enum l1d_flush_type types, bool enable) >>> #ifdef CONFIG_DEBUG_FS >>> static int rfi_flush_set(void *data, u64 val) >>> { >>> + bool enable; >>> + >>> if (val == 1) >>> - - rfi_flush_enable(true); >>> + enable = true; >>> else if (val == 0) >>> - - rfi_flush_enable(false); >>> + enable = false; >>> else >>> return -EINVAL; >>> >>> + /* Only do anything if we're changing state */ >>> + if (enable != rfi_flush) >>> + rfi_flush_enable(enable); >>> + >>> return 0; >>> } >>> >>> @@ -965,12 +963,4 @@ static __init int rfi_flush_debugfs_init(void) >>> } >>> device_initcall(rfi_flush_debugfs_init); >>> #endif >>> - - >>> - -ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, char *buf) >>> - -{ >>> - - if (rfi_flush) >>> - - return sprintf(buf, "Mitigation: RFI Flush\n"); >>> - - >>> - - return sprintf(buf, "Vulnerable\n"); >>> - -} >>> #endif /* CONFIG_PPC_BOOK3S_64 */ >>> diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S >>> index 072a23a17350..876ac9d52afc 100644 >>> - --- a/arch/powerpc/kernel/vmlinux.lds.S >>> +++ b/arch/powerpc/kernel/vmlinux.lds.S >>> @@ -73,14 +73,45 @@ SECTIONS >>> RODATA >>> >>> #ifdef CONFIG_PPC64 >>> + . = ALIGN(8); >>> + __stf_entry_barrier_fixup : AT(ADDR(__stf_entry_barrier_fixup) - LOAD_OFFSET) { >>> + __start___stf_entry_barrier_fixup = .; >>> + *(__stf_entry_barrier_fixup) >>> + __stop___stf_entry_barrier_fixup = .; >>> + } >>> + >>> + . = ALIGN(8); >>> + __stf_exit_barrier_fixup : AT(ADDR(__stf_exit_barrier_fixup) - LOAD_OFFSET) { >>> + __start___stf_exit_barrier_fixup = .; >>> + *(__stf_exit_barrier_fixup) >>> + __stop___stf_exit_barrier_fixup = .; >>> + } >>> + >>> . = ALIGN(8); >>> __rfi_flush_fixup : AT(ADDR(__rfi_flush_fixup) - LOAD_OFFSET) { >>> __start___rfi_flush_fixup = .; >>> *(__rfi_flush_fixup) >>> __stop___rfi_flush_fixup = .; >>> } >>> - -#endif >>> +#endif /* CONFIG_PPC64 */ >>> >>> +#ifdef CONFIG_PPC_BARRIER_NOSPEC >>> + . = ALIGN(8); >>> + __spec_barrier_fixup : AT(ADDR(__spec_barrier_fixup) - LOAD_OFFSET) { >>> + __start___barrier_nospec_fixup = .; >>> + *(__barrier_nospec_fixup) >>> + __stop___barrier_nospec_fixup = .; >>> + } >>> +#endif /* CONFIG_PPC_BARRIER_NOSPEC */ >>> + >>> +#ifdef CONFIG_PPC_FSL_BOOK3E >>> + . = ALIGN(8); >>> + __spec_btb_flush_fixup : AT(ADDR(__spec_btb_flush_fixup) - LOAD_OFFSET) { >>> + __start__btb_flush_fixup = .; >>> + *(__btb_flush_fixup) >>> + __stop__btb_flush_fixup = .; >>> + } >>> +#endif >>> EXCEPTION_TABLE(0) >>> >>> NOTES :kernel :notes >>> diff --git a/arch/powerpc/lib/code-patching.c b/arch/powerpc/lib/code-patching.c >>> index d5edbeb8eb82..570c06a00db6 100644 >>> - --- a/arch/powerpc/lib/code-patching.c >>> +++ b/arch/powerpc/lib/code-patching.c >>> @@ -14,12 +14,25 @@ >>> #include <asm/page.h> >>> #include <asm/code-patching.h> >>> #include <asm/uaccess.h> >>> +#include <asm/setup.h> >>> +#include <asm/sections.h> >>> >>> >>> +static inline bool is_init(unsigned int *addr) >>> +{ >>> + return addr >= (unsigned int *)__init_begin && addr < (unsigned int *)__init_end; >>> +} >>> + >>> int patch_instruction(unsigned int *addr, unsigned int instr) >>> { >>> int err; >>> >>> + /* Make sure we aren't patching a freed init section */ >>> + if (init_mem_is_free && is_init(addr)) { >>> + pr_debug("Skipping init section patching addr: 0x%px\n", addr); >>> + return 0; >>> + } >>> + >>> __put_user_size(instr, addr, 4, err); >>> if (err) >>> return err; >>> @@ -32,6 +45,22 @@ int patch_branch(unsigned int *addr, unsigned long target, int flags) >>> return patch_instruction(addr, create_branch(addr, target, flags)); >>> } >>> >>> +int patch_branch_site(s32 *site, unsigned long target, int flags) >>> +{ >>> + unsigned int *addr; >>> + >>> + addr = (unsigned int *)((unsigned long)site + *site); >>> + return patch_instruction(addr, create_branch(addr, target, flags)); >>> +} >>> + >>> +int patch_instruction_site(s32 *site, unsigned int instr) >>> +{ >>> + unsigned int *addr; >>> + >>> + addr = (unsigned int *)((unsigned long)site + *site); >>> + return patch_instruction(addr, instr); >>> +} >>> + >>> unsigned int create_branch(const unsigned int *addr, >>> unsigned long target, int flags) >>> { >>> diff --git a/arch/powerpc/lib/feature-fixups.c b/arch/powerpc/lib/feature-fixups.c >>> index 3af014684872..7bdfc19a491d 100644 >>> - --- a/arch/powerpc/lib/feature-fixups.c >>> +++ b/arch/powerpc/lib/feature-fixups.c >>> @@ -21,7 +21,7 @@ >>> #include <asm/page.h> >>> #include <asm/sections.h> >>> #include <asm/setup.h> >>> - - >>> +#include <asm/security_features.h> >>> >>> struct fixup_entry { >>> unsigned long mask; >>> @@ -115,6 +115,120 @@ void do_feature_fixups(unsigned long value, void *fixup_start, void *fixup_end) >>> } >>> >>> #ifdef CONFIG_PPC_BOOK3S_64 >>> +void do_stf_entry_barrier_fixups(enum stf_barrier_type types) >>> +{ >>> + unsigned int instrs[3], *dest; >>> + long *start, *end; >>> + int i; >>> + >>> + start = PTRRELOC(&__start___stf_entry_barrier_fixup), >>> + end = PTRRELOC(&__stop___stf_entry_barrier_fixup); >>> + >>> + instrs[0] = 0x60000000; /* nop */ >>> + instrs[1] = 0x60000000; /* nop */ >>> + instrs[2] = 0x60000000; /* nop */ >>> + >>> + i = 0; >>> + if (types & STF_BARRIER_FALLBACK) { >>> + instrs[i++] = 0x7d4802a6; /* mflr r10 */ >>> + instrs[i++] = 0x60000000; /* branch patched below */ >>> + instrs[i++] = 0x7d4803a6; /* mtlr r10 */ >>> + } else if (types & STF_BARRIER_EIEIO) { >>> + instrs[i++] = 0x7e0006ac; /* eieio + bit 6 hint */ >>> + } else if (types & STF_BARRIER_SYNC_ORI) { >>> + instrs[i++] = 0x7c0004ac; /* hwsync */ >>> + instrs[i++] = 0xe94d0000; /* ld r10,0(r13) */ >>> + instrs[i++] = 0x63ff0000; /* ori 31,31,0 speculation barrier */ >>> + } >>> + >>> + for (i = 0; start < end; start++, i++) { >>> + dest = (void *)start + *start; >>> + >>> + pr_devel("patching dest %lx\n", (unsigned long)dest); >>> + >>> + patch_instruction(dest, instrs[0]); >>> + >>> + if (types & STF_BARRIER_FALLBACK) >>> + patch_branch(dest + 1, (unsigned long)&stf_barrier_fallback, >>> + BRANCH_SET_LINK); >>> + else >>> + patch_instruction(dest + 1, instrs[1]); >>> + >>> + patch_instruction(dest + 2, instrs[2]); >>> + } >>> + >>> + printk(KERN_DEBUG "stf-barrier: patched %d entry locations (%s barrier)\n", i, >>> + (types == STF_BARRIER_NONE) ? "no" : >>> + (types == STF_BARRIER_FALLBACK) ? "fallback" : >>> + (types == STF_BARRIER_EIEIO) ? "eieio" : >>> + (types == (STF_BARRIER_SYNC_ORI)) ? "hwsync" >>> + : "unknown"); >>> +} >>> + >>> +void do_stf_exit_barrier_fixups(enum stf_barrier_type types) >>> +{ >>> + unsigned int instrs[6], *dest; >>> + long *start, *end; >>> + int i; >>> + >>> + start = PTRRELOC(&__start___stf_exit_barrier_fixup), >>> + end = PTRRELOC(&__stop___stf_exit_barrier_fixup); >>> + >>> + instrs[0] = 0x60000000; /* nop */ >>> + instrs[1] = 0x60000000; /* nop */ >>> + instrs[2] = 0x60000000; /* nop */ >>> + instrs[3] = 0x60000000; /* nop */ >>> + instrs[4] = 0x60000000; /* nop */ >>> + instrs[5] = 0x60000000; /* nop */ >>> + >>> + i = 0; >>> + if (types & STF_BARRIER_FALLBACK || types & STF_BARRIER_SYNC_ORI) { >>> + if (cpu_has_feature(CPU_FTR_HVMODE)) { >>> + instrs[i++] = 0x7db14ba6; /* mtspr 0x131, r13 (HSPRG1) */ >>> + instrs[i++] = 0x7db04aa6; /* mfspr r13, 0x130 (HSPRG0) */ >>> + } else { >>> + instrs[i++] = 0x7db243a6; /* mtsprg 2,r13 */ >>> + instrs[i++] = 0x7db142a6; /* mfsprg r13,1 */ >>> + } >>> + instrs[i++] = 0x7c0004ac; /* hwsync */ >>> + instrs[i++] = 0xe9ad0000; /* ld r13,0(r13) */ >>> + instrs[i++] = 0x63ff0000; /* ori 31,31,0 speculation barrier */ >>> + if (cpu_has_feature(CPU_FTR_HVMODE)) { >>> + instrs[i++] = 0x7db14aa6; /* mfspr r13, 0x131 (HSPRG1) */ >>> + } else { >>> + instrs[i++] = 0x7db242a6; /* mfsprg r13,2 */ >>> + } >>> + } else if (types & STF_BARRIER_EIEIO) { >>> + instrs[i++] = 0x7e0006ac; /* eieio + bit 6 hint */ >>> + } >>> + >>> + for (i = 0; start < end; start++, i++) { >>> + dest = (void *)start + *start; >>> + >>> + pr_devel("patching dest %lx\n", (unsigned long)dest); >>> + >>> + patch_instruction(dest, instrs[0]); >>> + patch_instruction(dest + 1, instrs[1]); >>> + patch_instruction(dest + 2, instrs[2]); >>> + patch_instruction(dest + 3, instrs[3]); >>> + patch_instruction(dest + 4, instrs[4]); >>> + patch_instruction(dest + 5, instrs[5]); >>> + } >>> + printk(KERN_DEBUG "stf-barrier: patched %d exit locations (%s barrier)\n", i, >>> + (types == STF_BARRIER_NONE) ? "no" : >>> + (types == STF_BARRIER_FALLBACK) ? "fallback" : >>> + (types == STF_BARRIER_EIEIO) ? "eieio" : >>> + (types == (STF_BARRIER_SYNC_ORI)) ? "hwsync" >>> + : "unknown"); >>> +} >>> + >>> + >>> +void do_stf_barrier_fixups(enum stf_barrier_type types) >>> +{ >>> + do_stf_entry_barrier_fixups(types); >>> + do_stf_exit_barrier_fixups(types); >>> +} >>> + >>> void do_rfi_flush_fixups(enum l1d_flush_type types) >>> { >>> unsigned int instrs[3], *dest; >>> @@ -151,10 +265,110 @@ void do_rfi_flush_fixups(enum l1d_flush_type types) >>> patch_instruction(dest + 2, instrs[2]); >>> } >>> >>> - - printk(KERN_DEBUG "rfi-flush: patched %d locations\n", i); >>> + printk(KERN_DEBUG "rfi-flush: patched %d locations (%s flush)\n", i, >>> + (types == L1D_FLUSH_NONE) ? "no" : >>> + (types == L1D_FLUSH_FALLBACK) ? "fallback displacement" : >>> + (types & L1D_FLUSH_ORI) ? (types & L1D_FLUSH_MTTRIG) >>> + ? "ori+mttrig type" >>> + : "ori type" : >>> + (types & L1D_FLUSH_MTTRIG) ? "mttrig type" >>> + : "unknown"); >>> +} >>> + >>> +void do_barrier_nospec_fixups_range(bool enable, void *fixup_start, void *fixup_end) >>> +{ >>> + unsigned int instr, *dest; >>> + long *start, *end; >>> + int i; >>> + >>> + start = fixup_start; >>> + end = fixup_end; >>> + >>> + instr = 0x60000000; /* nop */ >>> + >>> + if (enable) { >>> + pr_info("barrier-nospec: using ORI speculation barrier\n"); >>> + instr = 0x63ff0000; /* ori 31,31,0 speculation barrier */ >>> + } >>> + >>> + for (i = 0; start < end; start++, i++) { >>> + dest = (void *)start + *start; >>> + >>> + pr_devel("patching dest %lx\n", (unsigned long)dest); >>> + patch_instruction(dest, instr); >>> + } >>> + >>> + printk(KERN_DEBUG "barrier-nospec: patched %d locations\n", i); >>> } >>> + >>> #endif /* CONFIG_PPC_BOOK3S_64 */ >>> >>> +#ifdef CONFIG_PPC_BARRIER_NOSPEC >>> +void do_barrier_nospec_fixups(bool enable) >>> +{ >>> + void *start, *end; >>> + >>> + start = PTRRELOC(&__start___barrier_nospec_fixup), >>> + end = PTRRELOC(&__stop___barrier_nospec_fixup); >>> + >>> + do_barrier_nospec_fixups_range(enable, start, end); >>> +} >>> +#endif /* CONFIG_PPC_BARRIER_NOSPEC */ >>> + >>> +#ifdef CONFIG_PPC_FSL_BOOK3E >>> +void do_barrier_nospec_fixups_range(bool enable, void *fixup_start, void *fixup_end) >>> +{ >>> + unsigned int instr[2], *dest; >>> + long *start, *end; >>> + int i; >>> + >>> + start = fixup_start; >>> + end = fixup_end; >>> + >>> + instr[0] = PPC_INST_NOP; >>> + instr[1] = PPC_INST_NOP; >>> + >>> + if (enable) { >>> + pr_info("barrier-nospec: using isync; sync as speculation barrier\n"); >>> + instr[0] = PPC_INST_ISYNC; >>> + instr[1] = PPC_INST_SYNC; >>> + } >>> + >>> + for (i = 0; start < end; start++, i++) { >>> + dest = (void *)start + *start; >>> + >>> + pr_devel("patching dest %lx\n", (unsigned long)dest); >>> + patch_instruction(dest, instr[0]); >>> + patch_instruction(dest + 1, instr[1]); >>> + } >>> + >>> + printk(KERN_DEBUG "barrier-nospec: patched %d locations\n", i); >>> +} >>> + >>> +static void patch_btb_flush_section(long *curr) >>> +{ >>> + unsigned int *start, *end; >>> + >>> + start = (void *)curr + *curr; >>> + end = (void *)curr + *(curr + 1); >>> + for (; start < end; start++) { >>> + pr_devel("patching dest %lx\n", (unsigned long)start); >>> + patch_instruction(start, PPC_INST_NOP); >>> + } >>> +} >>> + >>> +void do_btb_flush_fixups(void) >>> +{ >>> + long *start, *end; >>> + >>> + start = PTRRELOC(&__start__btb_flush_fixup); >>> + end = PTRRELOC(&__stop__btb_flush_fixup); >>> + >>> + for (; start < end; start += 2) >>> + patch_btb_flush_section(start); >>> +} >>> +#endif /* CONFIG_PPC_FSL_BOOK3E */ >>> + >>> void do_lwsync_fixups(unsigned long value, void *fixup_start, void *fixup_end) >>> { >>> long *start, *end; >>> diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c >>> index 22d94c3e6fc4..1efe5ca5c3bc 100644 >>> - --- a/arch/powerpc/mm/mem.c >>> +++ b/arch/powerpc/mm/mem.c >>> @@ -62,6 +62,7 @@ >>> #endif >>> >>> unsigned long long memory_limit; >>> +bool init_mem_is_free; >>> >>> #ifdef CONFIG_HIGHMEM >>> pte_t *kmap_pte; >>> @@ -381,6 +382,7 @@ void __init mem_init(void) >>> void free_initmem(void) >>> { >>> ppc_md.progress = ppc_printk_progress; >>> + init_mem_is_free = true; >>> free_initmem_default(POISON_FREE_INITMEM); >>> } >>> >>> diff --git a/arch/powerpc/mm/tlb_low_64e.S b/arch/powerpc/mm/tlb_low_64e.S >>> index 29d6987c37ba..5486d56da289 100644 >>> - --- a/arch/powerpc/mm/tlb_low_64e.S >>> +++ b/arch/powerpc/mm/tlb_low_64e.S >>> @@ -69,6 +69,13 @@ END_FTR_SECTION_IFSET(CPU_FTR_EMB_HV) >>> std r15,EX_TLB_R15(r12) >>> std r10,EX_TLB_CR(r12) >>> #ifdef CONFIG_PPC_FSL_BOOK3E >>> +START_BTB_FLUSH_SECTION >>> + mfspr r11, SPRN_SRR1 >>> + andi. r10,r11,MSR_PR >>> + beq 1f >>> + BTB_FLUSH(r10) >>> +1: >>> +END_BTB_FLUSH_SECTION >>> std r7,EX_TLB_R7(r12) >>> #endif >>> TLB_MISS_PROLOG_STATS >>> diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c >>> index c57afc619b20..e14b52c7ebd8 100644 >>> - --- a/arch/powerpc/platforms/powernv/setup.c >>> +++ b/arch/powerpc/platforms/powernv/setup.c >>> @@ -37,53 +37,99 @@ >>> #include <asm/smp.h> >>> #include <asm/tm.h> >>> #include <asm/setup.h> >>> +#include <asm/security_features.h> >>> >>> #include "powernv.h" >>> >>> + >>> +static bool fw_feature_is(const char *state, const char *name, >>> + struct device_node *fw_features) >>> +{ >>> + struct device_node *np; >>> + bool rc = false; >>> + >>> + np = of_get_child_by_name(fw_features, name); >>> + if (np) { >>> + rc = of_property_read_bool(np, state); >>> + of_node_put(np); >>> + } >>> + >>> + return rc; >>> +} >>> + >>> +static void init_fw_feat_flags(struct device_node *np) >>> +{ >>> + if (fw_feature_is("enabled", "inst-spec-barrier-ori31,31,0", np)) >>> + security_ftr_set(SEC_FTR_SPEC_BAR_ORI31); >>> + >>> + if (fw_feature_is("enabled", "fw-bcctrl-serialized", np)) >>> + security_ftr_set(SEC_FTR_BCCTRL_SERIALISED); >>> + >>> + if (fw_feature_is("enabled", "inst-l1d-flush-ori30,30,0", np)) >>> + security_ftr_set(SEC_FTR_L1D_FLUSH_ORI30); >>> + >>> + if (fw_feature_is("enabled", "inst-l1d-flush-trig2", np)) >>> + security_ftr_set(SEC_FTR_L1D_FLUSH_TRIG2); >>> + >>> + if (fw_feature_is("enabled", "fw-l1d-thread-split", np)) >>> + security_ftr_set(SEC_FTR_L1D_THREAD_PRIV); >>> + >>> + if (fw_feature_is("enabled", "fw-count-cache-disabled", np)) >>> + security_ftr_set(SEC_FTR_COUNT_CACHE_DISABLED); >>> + >>> + if (fw_feature_is("enabled", "fw-count-cache-flush-bcctr2,0,0", np)) >>> + security_ftr_set(SEC_FTR_BCCTR_FLUSH_ASSIST); >>> + >>> + if (fw_feature_is("enabled", "needs-count-cache-flush-on-context-switch", np)) >>> + security_ftr_set(SEC_FTR_FLUSH_COUNT_CACHE); >>> + >>> + /* >>> + * The features below are enabled by default, so we instead look to see >>> + * if firmware has *disabled* them, and clear them if so. >>> + */ >>> + if (fw_feature_is("disabled", "speculation-policy-favor-security", np)) >>> + security_ftr_clear(SEC_FTR_FAVOUR_SECURITY); >>> + >>> + if (fw_feature_is("disabled", "needs-l1d-flush-msr-pr-0-to-1", np)) >>> + security_ftr_clear(SEC_FTR_L1D_FLUSH_PR); >>> + >>> + if (fw_feature_is("disabled", "needs-l1d-flush-msr-hv-1-to-0", np)) >>> + security_ftr_clear(SEC_FTR_L1D_FLUSH_HV); >>> + >>> + if (fw_feature_is("disabled", "needs-spec-barrier-for-bound-checks", np)) >>> + security_ftr_clear(SEC_FTR_BNDS_CHK_SPEC_BAR); >>> +} >>> + >>> static void pnv_setup_rfi_flush(void) >>> { >>> struct device_node *np, *fw_features; >>> enum l1d_flush_type type; >>> - - int enable; >>> + bool enable; >>> >>> /* Default to fallback in case fw-features are not available */ >>> type = L1D_FLUSH_FALLBACK; >>> - - enable = 1; >>> >>> np = of_find_node_by_name(NULL, "ibm,opal"); >>> fw_features = of_get_child_by_name(np, "fw-features"); >>> of_node_put(np); >>> >>> if (fw_features) { >>> - - np = of_get_child_by_name(fw_features, "inst-l1d-flush-trig2"); >>> - - if (np && of_property_read_bool(np, "enabled")) >>> - - type = L1D_FLUSH_MTTRIG; >>> + init_fw_feat_flags(fw_features); >>> + of_node_put(fw_features); >>> >>> - - of_node_put(np); >>> + if (security_ftr_enabled(SEC_FTR_L1D_FLUSH_TRIG2)) >>> + type = L1D_FLUSH_MTTRIG; >>> >>> - - np = of_get_child_by_name(fw_features, "inst-l1d-flush-ori30,30,0"); >>> - - if (np && of_property_read_bool(np, "enabled")) >>> + if (security_ftr_enabled(SEC_FTR_L1D_FLUSH_ORI30)) >>> type = L1D_FLUSH_ORI; >>> - - >>> - - of_node_put(np); >>> - - >>> - - /* Enable unless firmware says NOT to */ >>> - - enable = 2; >>> - - np = of_get_child_by_name(fw_features, "needs-l1d-flush-msr-hv-1-to-0"); >>> - - if (np && of_property_read_bool(np, "disabled")) >>> - - enable--; >>> - - >>> - - of_node_put(np); >>> - - >>> - - np = of_get_child_by_name(fw_features, "needs-l1d-flush-msr-pr-0-to-1"); >>> - - if (np && of_property_read_bool(np, "disabled")) >>> - - enable--; >>> - - >>> - - of_node_put(np); >>> - - of_node_put(fw_features); >>> } >>> >>> - - setup_rfi_flush(type, enable > 0); >>> + enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) && \ >>> + (security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR) || \ >>> + security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV)); >>> + >>> + setup_rfi_flush(type, enable); >>> + setup_count_cache_flush(); >>> } >>> >>> static void __init pnv_setup_arch(void) >>> @@ -91,6 +137,7 @@ static void __init pnv_setup_arch(void) >>> set_arch_panic_timeout(10, ARCH_PANIC_TIMEOUT); >>> >>> pnv_setup_rfi_flush(); >>> + setup_stf_barrier(); >>> >>> /* Initialize SMP */ >>> pnv_smp_init(); >>> diff --git a/arch/powerpc/platforms/pseries/mobility.c b/arch/powerpc/platforms/pseries/mobility.c >>> index 8dd0c8edefd6..c773396d0969 100644 >>> - --- a/arch/powerpc/platforms/pseries/mobility.c >>> +++ b/arch/powerpc/platforms/pseries/mobility.c >>> @@ -314,6 +314,9 @@ void post_mobility_fixup(void) >>> printk(KERN_ERR "Post-mobility device tree update " >>> "failed: %d\n", rc); >>> >>> + /* Possibly switch to a new RFI flush type */ >>> + pseries_setup_rfi_flush(); >>> + >>> return; >>> } >>> >>> diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h >>> index 8411c27293e4..e7d80797384d 100644 >>> - --- a/arch/powerpc/platforms/pseries/pseries.h >>> +++ b/arch/powerpc/platforms/pseries/pseries.h >>> @@ -81,4 +81,6 @@ extern struct pci_controller_ops pseries_pci_controller_ops; >>> >>> unsigned long pseries_memory_block_size(void); >>> >>> +void pseries_setup_rfi_flush(void); >>> + >>> #endif /* _PSERIES_PSERIES_H */ >>> diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c >>> index dd2545fc9947..9cc976ff7fec 100644 >>> - --- a/arch/powerpc/platforms/pseries/setup.c >>> +++ b/arch/powerpc/platforms/pseries/setup.c >>> @@ -67,6 +67,7 @@ >>> #include <asm/eeh.h> >>> #include <asm/reg.h> >>> #include <asm/plpar_wrappers.h> >>> +#include <asm/security_features.h> >>> >>> #include "pseries.h" >>> >>> @@ -499,37 +500,87 @@ static void __init find_and_init_phbs(void) >>> of_pci_check_probe_only(); >>> } >>> >>> - -static void pseries_setup_rfi_flush(void) >>> +static void init_cpu_char_feature_flags(struct h_cpu_char_result *result) >>> +{ >>> + /* >>> + * The features below are disabled by default, so we instead look to see >>> + * if firmware has *enabled* them, and set them if so. >>> + */ >>> + if (result->character & H_CPU_CHAR_SPEC_BAR_ORI31) >>> + security_ftr_set(SEC_FTR_SPEC_BAR_ORI31); >>> + >>> + if (result->character & H_CPU_CHAR_BCCTRL_SERIALISED) >>> + security_ftr_set(SEC_FTR_BCCTRL_SERIALISED); >>> + >>> + if (result->character & H_CPU_CHAR_L1D_FLUSH_ORI30) >>> + security_ftr_set(SEC_FTR_L1D_FLUSH_ORI30); >>> + >>> + if (result->character & H_CPU_CHAR_L1D_FLUSH_TRIG2) >>> + security_ftr_set(SEC_FTR_L1D_FLUSH_TRIG2); >>> + >>> + if (result->character & H_CPU_CHAR_L1D_THREAD_PRIV) >>> + security_ftr_set(SEC_FTR_L1D_THREAD_PRIV); >>> + >>> + if (result->character & H_CPU_CHAR_COUNT_CACHE_DISABLED) >>> + security_ftr_set(SEC_FTR_COUNT_CACHE_DISABLED); >>> + >>> + if (result->character & H_CPU_CHAR_BCCTR_FLUSH_ASSIST) >>> + security_ftr_set(SEC_FTR_BCCTR_FLUSH_ASSIST); >>> + >>> + if (result->behaviour & H_CPU_BEHAV_FLUSH_COUNT_CACHE) >>> + security_ftr_set(SEC_FTR_FLUSH_COUNT_CACHE); >>> + >>> + /* >>> + * The features below are enabled by default, so we instead look to see >>> + * if firmware has *disabled* them, and clear them if so. >>> + */ >>> + if (!(result->behaviour & H_CPU_BEHAV_FAVOUR_SECURITY)) >>> + security_ftr_clear(SEC_FTR_FAVOUR_SECURITY); >>> + >>> + if (!(result->behaviour & H_CPU_BEHAV_L1D_FLUSH_PR)) >>> + security_ftr_clear(SEC_FTR_L1D_FLUSH_PR); >>> + >>> + if (!(result->behaviour & H_CPU_BEHAV_BNDS_CHK_SPEC_BAR)) >>> + security_ftr_clear(SEC_FTR_BNDS_CHK_SPEC_BAR); >>> +} >>> + >>> +void pseries_setup_rfi_flush(void) >>> { >>> struct h_cpu_char_result result; >>> enum l1d_flush_type types; >>> bool enable; >>> long rc; >>> >>> - - /* Enable by default */ >>> - - enable = true; >>> + /* >>> + * Set features to the defaults assumed by init_cpu_char_feature_flags() >>> + * so it can set/clear again any features that might have changed after >>> + * migration, and in case the hypercall fails and it is not even called. >>> + */ >>> + powerpc_security_features = SEC_FTR_DEFAULT; >>> >>> rc = plpar_get_cpu_characteristics(&result); >>> - - if (rc == H_SUCCESS) { >>> - - types = L1D_FLUSH_NONE; >>> + if (rc == H_SUCCESS) >>> + init_cpu_char_feature_flags(&result); >>> >>> - - if (result.character & H_CPU_CHAR_L1D_FLUSH_TRIG2) >>> - - types |= L1D_FLUSH_MTTRIG; >>> - - if (result.character & H_CPU_CHAR_L1D_FLUSH_ORI30) >>> - - types |= L1D_FLUSH_ORI; >>> + /* >>> + * We're the guest so this doesn't apply to us, clear it to simplify >>> + * handling of it elsewhere. >>> + */ >>> + security_ftr_clear(SEC_FTR_L1D_FLUSH_HV); >>> >>> - - /* Use fallback if nothing set in hcall */ >>> - - if (types == L1D_FLUSH_NONE) >>> - - types = L1D_FLUSH_FALLBACK; >>> + types = L1D_FLUSH_FALLBACK; >>> >>> - - if (!(result.behaviour & H_CPU_BEHAV_L1D_FLUSH_PR)) >>> - - enable = false; >>> - - } else { >>> - - /* Default to fallback if case hcall is not available */ >>> - - types = L1D_FLUSH_FALLBACK; >>> - - } >>> + if (security_ftr_enabled(SEC_FTR_L1D_FLUSH_TRIG2)) >>> + types |= L1D_FLUSH_MTTRIG; >>> + >>> + if (security_ftr_enabled(SEC_FTR_L1D_FLUSH_ORI30)) >>> + types |= L1D_FLUSH_ORI; >>> + >>> + enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) && \ >>> + security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR); >>> >>> setup_rfi_flush(types, enable); >>> + setup_count_cache_flush(); >>> } >>> >>> static void __init pSeries_setup_arch(void) >>> @@ -549,6 +600,7 @@ static void __init pSeries_setup_arch(void) >>> fwnmi_init(); >>> >>> pseries_setup_rfi_flush(); >>> + setup_stf_barrier(); >>> >>> /* By default, only probe PCI (can be overridden by rtas_pci) */ >>> pci_add_flags(PCI_PROBE_ONLY); >>> diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c >>> index 786bf01691c9..83619ebede93 100644 >>> - --- a/arch/powerpc/xmon/xmon.c >>> +++ b/arch/powerpc/xmon/xmon.c >>> @@ -2144,6 +2144,8 @@ static void dump_one_paca(int cpu) >>> DUMP(p, slb_cache_ptr, "x"); >>> for (i = 0; i < SLB_CACHE_ENTRIES; i++) >>> printf(" slb_cache[%d]: = 0x%016lx\n", i, p->slb_cache[i]); >>> + >>> + DUMP(p, rfi_flush_fallback_area, "px"); >>> #endif >>> DUMP(p, dscr_default, "llx"); >>> #ifdef CONFIG_PPC_BOOK3E >>> - -- >>> 2.20.1 >>> >>> -----BEGIN PGP SIGNATURE----- >>> >>> iQIcBAEBAgAGBQJcvHWhAAoJEFHr6jzI4aWA6nsP/0YskmAfLovcUmERQ7+bIjq6 >>> IcS1T466dvy6MlqeBXU4x8pVgInWeHKEC9XJdkM1lOeib/SLW7Hbz4kgJeOGwFGY >>> lOTaexrxvsBqPm7f6GC0zbl9obEIIIIUs+TielFQANBgqm+q8Wio+XXPP9bpKeKY >>> agSpQ3nwL/PYixznbNmN/lP9py5p89LQ0IBcR7dDBGGWJtD/AXeZ9hslsZxPbPtI >>> nZJ0vdnjuoB2z+hCxfKWlYfLwH0VfoTpqP5x3ALCkvbBr67e8bf6EK8+trnvhyQ8 >>> iLY4bp1pm2epAI0/3NfyEiDMsGjVJ6IFlkyhDkHJgJNu0BGcGOSX2GpyU3juviAK >>> c95FtBft/i8AwigOMCivg2mN5edYjsSiPoEItwT5KWqgByJsdr5i5mYVx8cUjMOz >>> iAxLZCdg+UHZYuCBCAO2ZI1G9bVXI1Pa3btMspiCOOOsYGjXGf0oFfKQ+7957hUO >>> ftYYJoGHlMHiHR1OPas6T3lk6YKF9uvfIDTE3OKw2obHbbRz3u82xoWMRGW503MN >>> 7WpkpAP7oZ9RgqIWFVhatWy5f+7GFL0akEi4o2tsZHhYlPau7YWo+nToTd87itwt >>> GBaWJipzge4s13VkhAE+jWFO35Fvwi8uNZ7UgpuKMBECEjkGbtzBTq2MjSF5G8wc >>> yPEod5jby/Iqb7DkGPVG >>> =6DnF >>> -----END PGP SIGNATURE----- >>>