On 4/28/2019 9:19 AM, Michael Ellerman wrote:
Diana Madalina Craciun diana.craciun@nxp.com 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))) { \
  __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \barrier_nospec(); \- } \ (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))) {
  return __copy_tofrom_user((__force void __user *)to, from, n);barrier_nospec();- } memset(to, 0, n); return n;
 } @@ -359,21 +366,27 @@ static inline unsigned long __copy_from_user_inatomic(void *to, switch (n) { case 1:
 case 2:barrier_nospec(); __get_user_size(*(u8 *)to, from, 1, ret); break; case 4:barrier_nospec(); __get_user_size(*(u16 *)to, from, 2, ret); break; case 8:barrier_nospec(); __get_user_size(*(u32 *)to, from, 4, ret); break; } if (ret == 0) return 0; }barrier_nospec(); __get_user_size(*(u64 *)to, from, 8, ret); break;- 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)
 mfctr r9 ld r10,PACA_RFI_FLUSH_FALLBACK_AREA(r13)
- std r8,PACA_EXRFI+EX_R13(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)
 GET_SCRATCH0(r13); rfid
- ld r8,PACA_EXRFI+EX_R13(r13)
 @@ -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)
 mfctr r9 ld r10,PACA_RFI_FLUSH_FALLBACK_AREA(r13)
- std r8,PACA_EXRFI+EX_R13(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)
 GET_SCRATCH0(r13); hrfid
- ld r8,PACA_EXRFI+EX_R13(r13)
 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");elseseq_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");
 init_fallback_flush(); }pr_info("rfi-flush: fallback displacement flush available\n");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);
 else if (val == 0)enable = true;
rfi_flush_enable(false);
 else return -EINVAL;enable = false;
- /* 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);elsepatch_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-----