[PATCH stable v4.4 00/52] powerpc spectre backports for 4.4

Diana Madalina Craciun diana.craciun at nxp.com
Tue Apr 30 01:52:36 AEST 2019


On 4/28/2019 9:19 AM, Michael Ellerman wrote:
> Diana Madalina Craciun <diana.craciun at 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 at h;		\
>>> +	ori reg,reg,BUCSR_INIT at 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-----
>>>



More information about the Linuxppc-dev mailing list