xref: /linux-6.15/arch/powerpc/kernel/security.c (revision b2a6f604)
19a868f63SMichael Ellerman // SPDX-License-Identifier: GPL-2.0+
29a868f63SMichael Ellerman //
39a868f63SMichael Ellerman // Security related flags and so on.
49a868f63SMichael Ellerman //
59a868f63SMichael Ellerman // Copyright 2018, Michael Ellerman, IBM Corporation.
69a868f63SMichael Ellerman 
742e2acdeSBreno Leitao #include <linux/cpu.h>
89a868f63SMichael Ellerman #include <linux/kernel.h>
98ad33041SMichael Ellerman #include <linux/device.h>
10c6b4c914SMichael Ellerman #include <linux/memblock.h>
11d93e5e2dSMichael Ellerman #include <linux/nospec.h>
12d93e5e2dSMichael Ellerman #include <linux/prctl.h>
13ff348355SMichael Ellerman #include <linux/seq_buf.h>
14dbf77fedSAneesh Kumar K.V #include <linux/debugfs.h>
158ad33041SMichael Ellerman 
16ee13cb24SMichael Ellerman #include <asm/asm-prototypes.h>
17ee13cb24SMichael Ellerman #include <asm/code-patching.h>
189a868f63SMichael Ellerman #include <asm/security_features.h>
192eea7f06SMichal Suchanek #include <asm/setup.h>
2075346251SJordan Niethe #include <asm/inst.h>
219a868f63SMichael Ellerman 
22c6b4c914SMichael Ellerman #include "setup.h"
239a868f63SMichael Ellerman 
243b05a1e5SGeert Uytterhoeven u64 powerpc_security_features __read_mostly = SEC_FTR_DEFAULT;
258ad33041SMichael Ellerman 
261026798cSNicholas Piggin enum branch_cache_flush_type {
271026798cSNicholas Piggin 	BRANCH_CACHE_FLUSH_NONE	= 0x1,
281026798cSNicholas Piggin 	BRANCH_CACHE_FLUSH_SW	= 0x2,
291026798cSNicholas Piggin 	BRANCH_CACHE_FLUSH_HW	= 0x4,
30ee13cb24SMichael Ellerman };
311026798cSNicholas Piggin static enum branch_cache_flush_type count_cache_flush_type = BRANCH_CACHE_FLUSH_NONE;
32c06ac277SNicholas Piggin static enum branch_cache_flush_type link_stack_flush_type = BRANCH_CACHE_FLUSH_NONE;
33ee13cb24SMichael Ellerman 
34815069caSMichal Suchanek bool barrier_nospec_enabled;
35cf175dc3SDiana Craciun static bool no_nospec;
36f633a8adSDiana Craciun static bool btb_flush_enabled;
37d8f0e0b0SChristopher M. Riedl #if defined(CONFIG_PPC_FSL_BOOK3E) || defined(CONFIG_PPC_BOOK3S_64)
38f633a8adSDiana Craciun static bool no_spectrev2;
39f633a8adSDiana Craciun #endif
402eea7f06SMichal Suchanek 
412eea7f06SMichal Suchanek static void enable_barrier_nospec(bool enable)
422eea7f06SMichal Suchanek {
432eea7f06SMichal Suchanek 	barrier_nospec_enabled = enable;
442eea7f06SMichal Suchanek 	do_barrier_nospec_fixups(enable);
452eea7f06SMichal Suchanek }
462eea7f06SMichal Suchanek 
47d276960dSNick Child void __init setup_barrier_nospec(void)
48cb3d6759SMichal Suchanek {
49cb3d6759SMichal Suchanek 	bool enable;
50cb3d6759SMichal Suchanek 
51cb3d6759SMichal Suchanek 	/*
52cb3d6759SMichal Suchanek 	 * It would make sense to check SEC_FTR_SPEC_BAR_ORI31 below as well.
53cb3d6759SMichal Suchanek 	 * But there's a good reason not to. The two flags we check below are
54cb3d6759SMichal Suchanek 	 * both are enabled by default in the kernel, so if the hcall is not
55cb3d6759SMichal Suchanek 	 * functional they will be enabled.
56cb3d6759SMichal Suchanek 	 * On a system where the host firmware has been updated (so the ori
57cb3d6759SMichal Suchanek 	 * functions as a barrier), but on which the hypervisor (KVM/Qemu) has
58cb3d6759SMichal Suchanek 	 * not been updated, we would like to enable the barrier. Dropping the
59cb3d6759SMichal Suchanek 	 * check for SEC_FTR_SPEC_BAR_ORI31 achieves that. The only downside is
60cb3d6759SMichal Suchanek 	 * we potentially enable the barrier on systems where the host firmware
61cb3d6759SMichal Suchanek 	 * is not updated, but that's harmless as it's a no-op.
62cb3d6759SMichal Suchanek 	 */
63cb3d6759SMichal Suchanek 	enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) &&
64cb3d6759SMichal Suchanek 		 security_ftr_enabled(SEC_FTR_BNDS_CHK_SPEC_BAR);
65cb3d6759SMichal Suchanek 
66782e69efSJosh Poimboeuf 	if (!no_nospec && !cpu_mitigations_off())
67cb3d6759SMichal Suchanek 		enable_barrier_nospec(enable);
68cb3d6759SMichal Suchanek }
69cb3d6759SMichal Suchanek 
70cf175dc3SDiana Craciun static int __init handle_nospectre_v1(char *p)
71cf175dc3SDiana Craciun {
72cf175dc3SDiana Craciun 	no_nospec = true;
73cf175dc3SDiana Craciun 
74cf175dc3SDiana Craciun 	return 0;
75cf175dc3SDiana Craciun }
76cf175dc3SDiana Craciun early_param("nospectre_v1", handle_nospectre_v1);
77cf175dc3SDiana Craciun 
78cb3d6759SMichal Suchanek #ifdef CONFIG_DEBUG_FS
79cb3d6759SMichal Suchanek static int barrier_nospec_set(void *data, u64 val)
80cb3d6759SMichal Suchanek {
81cb3d6759SMichal Suchanek 	switch (val) {
82cb3d6759SMichal Suchanek 	case 0:
83cb3d6759SMichal Suchanek 	case 1:
84cb3d6759SMichal Suchanek 		break;
85cb3d6759SMichal Suchanek 	default:
86cb3d6759SMichal Suchanek 		return -EINVAL;
87cb3d6759SMichal Suchanek 	}
88cb3d6759SMichal Suchanek 
89cb3d6759SMichal Suchanek 	if (!!val == !!barrier_nospec_enabled)
90cb3d6759SMichal Suchanek 		return 0;
91cb3d6759SMichal Suchanek 
92cb3d6759SMichal Suchanek 	enable_barrier_nospec(!!val);
93cb3d6759SMichal Suchanek 
94cb3d6759SMichal Suchanek 	return 0;
95cb3d6759SMichal Suchanek }
96cb3d6759SMichal Suchanek 
97cb3d6759SMichal Suchanek static int barrier_nospec_get(void *data, u64 *val)
98cb3d6759SMichal Suchanek {
99cb3d6759SMichal Suchanek 	*val = barrier_nospec_enabled ? 1 : 0;
100cb3d6759SMichal Suchanek 	return 0;
101cb3d6759SMichal Suchanek }
102cb3d6759SMichal Suchanek 
103090d5ab9SYueHaibing DEFINE_DEBUGFS_ATTRIBUTE(fops_barrier_nospec, barrier_nospec_get,
104090d5ab9SYueHaibing 			 barrier_nospec_set, "%llu\n");
105cb3d6759SMichal Suchanek 
106cb3d6759SMichal Suchanek static __init int barrier_nospec_debugfs_init(void)
107cb3d6759SMichal Suchanek {
108090d5ab9SYueHaibing 	debugfs_create_file_unsafe("barrier_nospec", 0600,
109dbf77fedSAneesh Kumar K.V 				   arch_debugfs_dir, NULL,
110cb3d6759SMichal Suchanek 				   &fops_barrier_nospec);
111cb3d6759SMichal Suchanek 	return 0;
112cb3d6759SMichal Suchanek }
113cb3d6759SMichal Suchanek device_initcall(barrier_nospec_debugfs_init);
114398af571SMichael Ellerman 
115398af571SMichael Ellerman static __init int security_feature_debugfs_init(void)
116398af571SMichael Ellerman {
117dbf77fedSAneesh Kumar K.V 	debugfs_create_x64("security_features", 0400, arch_debugfs_dir,
1183b05a1e5SGeert Uytterhoeven 			   &powerpc_security_features);
119398af571SMichael Ellerman 	return 0;
120398af571SMichael Ellerman }
121398af571SMichael Ellerman device_initcall(security_feature_debugfs_init);
122cb3d6759SMichal Suchanek #endif /* CONFIG_DEBUG_FS */
123cb3d6759SMichal Suchanek 
124d8f0e0b0SChristopher M. Riedl #if defined(CONFIG_PPC_FSL_BOOK3E) || defined(CONFIG_PPC_BOOK3S_64)
125f633a8adSDiana Craciun static int __init handle_nospectre_v2(char *p)
126f633a8adSDiana Craciun {
127f633a8adSDiana Craciun 	no_spectrev2 = true;
128f633a8adSDiana Craciun 
129f633a8adSDiana Craciun 	return 0;
130f633a8adSDiana Craciun }
131f633a8adSDiana Craciun early_param("nospectre_v2", handle_nospectre_v2);
132d8f0e0b0SChristopher M. Riedl #endif /* CONFIG_PPC_FSL_BOOK3E || CONFIG_PPC_BOOK3S_64 */
133d8f0e0b0SChristopher M. Riedl 
134d8f0e0b0SChristopher M. Riedl #ifdef CONFIG_PPC_FSL_BOOK3E
135d276960dSNick Child void __init setup_spectre_v2(void)
136f633a8adSDiana Craciun {
137782e69efSJosh Poimboeuf 	if (no_spectrev2 || cpu_mitigations_off())
138f633a8adSDiana Craciun 		do_btb_flush_fixups();
139f633a8adSDiana Craciun 	else
140f633a8adSDiana Craciun 		btb_flush_enabled = true;
141f633a8adSDiana Craciun }
142f633a8adSDiana Craciun #endif /* CONFIG_PPC_FSL_BOOK3E */
143f633a8adSDiana Craciun 
144406d2b6aSDiana Craciun #ifdef CONFIG_PPC_BOOK3S_64
1458ad33041SMichael Ellerman ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, char *buf)
1468ad33041SMichael Ellerman {
147ff348355SMichael Ellerman 	bool thread_priv;
148ff348355SMichael Ellerman 
149ff348355SMichael Ellerman 	thread_priv = security_ftr_enabled(SEC_FTR_L1D_THREAD_PRIV);
150ff348355SMichael Ellerman 
1514e706af3SGustavo L. F. Walbon 	if (rfi_flush) {
152ff348355SMichael Ellerman 		struct seq_buf s;
153ff348355SMichael Ellerman 		seq_buf_init(&s, buf, PAGE_SIZE - 1);
154ff348355SMichael Ellerman 
1554e706af3SGustavo L. F. Walbon 		seq_buf_printf(&s, "Mitigation: RFI Flush");
156ff348355SMichael Ellerman 		if (thread_priv)
1574e706af3SGustavo L. F. Walbon 			seq_buf_printf(&s, ", L1D private per thread");
158ff348355SMichael Ellerman 
159ff348355SMichael Ellerman 		seq_buf_printf(&s, "\n");
160ff348355SMichael Ellerman 
161ff348355SMichael Ellerman 		return s.len;
162ff348355SMichael Ellerman 	}
163ff348355SMichael Ellerman 
1644e706af3SGustavo L. F. Walbon 	if (thread_priv)
1654e706af3SGustavo L. F. Walbon 		return sprintf(buf, "Vulnerable: L1D private per thread\n");
1664e706af3SGustavo L. F. Walbon 
167ff348355SMichael Ellerman 	if (!security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) &&
168ff348355SMichael Ellerman 	    !security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR))
169ff348355SMichael Ellerman 		return sprintf(buf, "Not affected\n");
1708ad33041SMichael Ellerman 
1718ad33041SMichael Ellerman 	return sprintf(buf, "Vulnerable\n");
1728ad33041SMichael Ellerman }
1738e6b6da9SAnthony Steinhauser 
1748e6b6da9SAnthony Steinhauser ssize_t cpu_show_l1tf(struct device *dev, struct device_attribute *attr, char *buf)
1758e6b6da9SAnthony Steinhauser {
1768e6b6da9SAnthony Steinhauser 	return cpu_show_meltdown(dev, attr, buf);
1778e6b6da9SAnthony Steinhauser }
178406d2b6aSDiana Craciun #endif
17956986016SMichael Ellerman 
18056986016SMichael Ellerman ssize_t cpu_show_spectre_v1(struct device *dev, struct device_attribute *attr, char *buf)
18156986016SMichael Ellerman {
1826d44acaeSMichael Ellerman 	struct seq_buf s;
18356986016SMichael Ellerman 
1846d44acaeSMichael Ellerman 	seq_buf_init(&s, buf, PAGE_SIZE - 1);
1856d44acaeSMichael Ellerman 
1866d44acaeSMichael Ellerman 	if (security_ftr_enabled(SEC_FTR_BNDS_CHK_SPEC_BAR)) {
187a3775145SMichal Suchanek 		if (barrier_nospec_enabled)
1886d44acaeSMichael Ellerman 			seq_buf_printf(&s, "Mitigation: __user pointer sanitization");
1896d44acaeSMichael Ellerman 		else
1906d44acaeSMichael Ellerman 			seq_buf_printf(&s, "Vulnerable");
191a3775145SMichal Suchanek 
1926d44acaeSMichael Ellerman 		if (security_ftr_enabled(SEC_FTR_SPEC_BAR_ORI31))
1936d44acaeSMichael Ellerman 			seq_buf_printf(&s, ", ori31 speculation barrier enabled");
1946d44acaeSMichael Ellerman 
1956d44acaeSMichael Ellerman 		seq_buf_printf(&s, "\n");
1966d44acaeSMichael Ellerman 	} else
1976d44acaeSMichael Ellerman 		seq_buf_printf(&s, "Not affected\n");
1986d44acaeSMichael Ellerman 
1996d44acaeSMichael Ellerman 	return s.len;
20056986016SMichael Ellerman }
201d6fbe1c5SMichael Ellerman 
202d6fbe1c5SMichael Ellerman ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr, char *buf)
203d6fbe1c5SMichael Ellerman {
204d6fbe1c5SMichael Ellerman 	struct seq_buf s;
2056d44acaeSMichael Ellerman 	bool bcs, ccd;
206d6fbe1c5SMichael Ellerman 
207d6fbe1c5SMichael Ellerman 	seq_buf_init(&s, buf, PAGE_SIZE - 1);
208d6fbe1c5SMichael Ellerman 
209d6fbe1c5SMichael Ellerman 	bcs = security_ftr_enabled(SEC_FTR_BCCTRL_SERIALISED);
210d6fbe1c5SMichael Ellerman 	ccd = security_ftr_enabled(SEC_FTR_COUNT_CACHE_DISABLED);
211d6fbe1c5SMichael Ellerman 
21292edf8dfSMichael Ellerman 	if (bcs || ccd) {
213d6fbe1c5SMichael Ellerman 		seq_buf_printf(&s, "Mitigation: ");
214d6fbe1c5SMichael Ellerman 
21592edf8dfSMichael Ellerman 		if (bcs)
216d6fbe1c5SMichael Ellerman 			seq_buf_printf(&s, "Indirect branch serialisation (kernel only)");
217d6fbe1c5SMichael Ellerman 
21892edf8dfSMichael Ellerman 		if (bcs && ccd)
219ee13cb24SMichael Ellerman 			seq_buf_printf(&s, ", ");
22092edf8dfSMichael Ellerman 
22192edf8dfSMichael Ellerman 		if (ccd)
222ee13cb24SMichael Ellerman 			seq_buf_printf(&s, "Indirect branch cache disabled");
22339e72bf9SMichael Ellerman 
2241026798cSNicholas Piggin 	} else if (count_cache_flush_type != BRANCH_CACHE_FLUSH_NONE) {
22592edf8dfSMichael Ellerman 		seq_buf_printf(&s, "Mitigation: Software count cache flush");
226ee13cb24SMichael Ellerman 
2271026798cSNicholas Piggin 		if (count_cache_flush_type == BRANCH_CACHE_FLUSH_HW)
228ee13cb24SMichael Ellerman 			seq_buf_printf(&s, " (hardware accelerated)");
22939e72bf9SMichael Ellerman 
230dfa88658SDiana Craciun 	} else if (btb_flush_enabled) {
231dfa88658SDiana Craciun 		seq_buf_printf(&s, "Mitigation: Branch predictor state flush");
232dfa88658SDiana Craciun 	} else {
233d6fbe1c5SMichael Ellerman 		seq_buf_printf(&s, "Vulnerable");
234dfa88658SDiana Craciun 	}
235d6fbe1c5SMichael Ellerman 
2364d24e21cSNicholas Piggin 	if (bcs || ccd || count_cache_flush_type != BRANCH_CACHE_FLUSH_NONE) {
2374d24e21cSNicholas Piggin 		if (link_stack_flush_type != BRANCH_CACHE_FLUSH_NONE)
2384d24e21cSNicholas Piggin 			seq_buf_printf(&s, ", Software link stack flush");
2394d24e21cSNicholas Piggin 		if (link_stack_flush_type == BRANCH_CACHE_FLUSH_HW)
2404d24e21cSNicholas Piggin 			seq_buf_printf(&s, " (hardware accelerated)");
2414d24e21cSNicholas Piggin 	}
2424d24e21cSNicholas Piggin 
243d6fbe1c5SMichael Ellerman 	seq_buf_printf(&s, "\n");
244d6fbe1c5SMichael Ellerman 
245d6fbe1c5SMichael Ellerman 	return s.len;
246d6fbe1c5SMichael Ellerman }
247a048a07dSNicholas Piggin 
2486453b532SDiana Craciun #ifdef CONFIG_PPC_BOOK3S_64
249a048a07dSNicholas Piggin /*
250a048a07dSNicholas Piggin  * Store-forwarding barrier support.
251a048a07dSNicholas Piggin  */
252a048a07dSNicholas Piggin 
253a048a07dSNicholas Piggin static enum stf_barrier_type stf_enabled_flush_types;
254a048a07dSNicholas Piggin static bool no_stf_barrier;
2557f262b4dSLi Huafei static bool stf_barrier;
256a048a07dSNicholas Piggin 
257a048a07dSNicholas Piggin static int __init handle_no_stf_barrier(char *p)
258a048a07dSNicholas Piggin {
259a048a07dSNicholas Piggin 	pr_info("stf-barrier: disabled on command line.");
260a048a07dSNicholas Piggin 	no_stf_barrier = true;
261a048a07dSNicholas Piggin 	return 0;
262a048a07dSNicholas Piggin }
263a048a07dSNicholas Piggin 
264a048a07dSNicholas Piggin early_param("no_stf_barrier", handle_no_stf_barrier);
265a048a07dSNicholas Piggin 
26603090592SNaveen N. Rao enum stf_barrier_type stf_barrier_type_get(void)
26703090592SNaveen N. Rao {
26803090592SNaveen N. Rao 	return stf_enabled_flush_types;
26903090592SNaveen N. Rao }
27003090592SNaveen N. Rao 
271a048a07dSNicholas Piggin /* This is the generic flag used by other architectures */
272a048a07dSNicholas Piggin static int __init handle_ssbd(char *p)
273a048a07dSNicholas Piggin {
274a048a07dSNicholas Piggin 	if (!p || strncmp(p, "auto", 5) == 0 || strncmp(p, "on", 2) == 0 ) {
275a048a07dSNicholas Piggin 		/* Until firmware tells us, we have the barrier with auto */
276a048a07dSNicholas Piggin 		return 0;
277a048a07dSNicholas Piggin 	} else if (strncmp(p, "off", 3) == 0) {
278a048a07dSNicholas Piggin 		handle_no_stf_barrier(NULL);
279a048a07dSNicholas Piggin 		return 0;
280a048a07dSNicholas Piggin 	} else
281a048a07dSNicholas Piggin 		return 1;
282a048a07dSNicholas Piggin 
283a048a07dSNicholas Piggin 	return 0;
284a048a07dSNicholas Piggin }
285a048a07dSNicholas Piggin early_param("spec_store_bypass_disable", handle_ssbd);
286a048a07dSNicholas Piggin 
287a048a07dSNicholas Piggin /* This is the generic flag used by other architectures */
288a048a07dSNicholas Piggin static int __init handle_no_ssbd(char *p)
289a048a07dSNicholas Piggin {
290a048a07dSNicholas Piggin 	handle_no_stf_barrier(NULL);
291a048a07dSNicholas Piggin 	return 0;
292a048a07dSNicholas Piggin }
293a048a07dSNicholas Piggin early_param("nospec_store_bypass_disable", handle_no_ssbd);
294a048a07dSNicholas Piggin 
295a048a07dSNicholas Piggin static void stf_barrier_enable(bool enable)
296a048a07dSNicholas Piggin {
297a048a07dSNicholas Piggin 	if (enable)
298a048a07dSNicholas Piggin 		do_stf_barrier_fixups(stf_enabled_flush_types);
299a048a07dSNicholas Piggin 	else
300a048a07dSNicholas Piggin 		do_stf_barrier_fixups(STF_BARRIER_NONE);
301a048a07dSNicholas Piggin 
302a048a07dSNicholas Piggin 	stf_barrier = enable;
303a048a07dSNicholas Piggin }
304a048a07dSNicholas Piggin 
305a048a07dSNicholas Piggin void setup_stf_barrier(void)
306a048a07dSNicholas Piggin {
307a048a07dSNicholas Piggin 	enum stf_barrier_type type;
30884ed26fdSNicholas Piggin 	bool enable;
309a048a07dSNicholas Piggin 
310a048a07dSNicholas Piggin 	/* Default to fallback in case fw-features are not available */
311a048a07dSNicholas Piggin 	if (cpu_has_feature(CPU_FTR_ARCH_300))
312a048a07dSNicholas Piggin 		type = STF_BARRIER_EIEIO;
313a048a07dSNicholas Piggin 	else if (cpu_has_feature(CPU_FTR_ARCH_207S))
314a048a07dSNicholas Piggin 		type = STF_BARRIER_SYNC_ORI;
315a048a07dSNicholas Piggin 	else if (cpu_has_feature(CPU_FTR_ARCH_206))
316a048a07dSNicholas Piggin 		type = STF_BARRIER_FALLBACK;
317a048a07dSNicholas Piggin 	else
318a048a07dSNicholas Piggin 		type = STF_BARRIER_NONE;
319a048a07dSNicholas Piggin 
320a048a07dSNicholas Piggin 	enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) &&
32184ed26fdSNicholas Piggin 		 security_ftr_enabled(SEC_FTR_STF_BARRIER);
322a048a07dSNicholas Piggin 
323a048a07dSNicholas Piggin 	if (type == STF_BARRIER_FALLBACK) {
324a048a07dSNicholas Piggin 		pr_info("stf-barrier: fallback barrier available\n");
325a048a07dSNicholas Piggin 	} else if (type == STF_BARRIER_SYNC_ORI) {
326a048a07dSNicholas Piggin 		pr_info("stf-barrier: hwsync barrier available\n");
327a048a07dSNicholas Piggin 	} else if (type == STF_BARRIER_EIEIO) {
328a048a07dSNicholas Piggin 		pr_info("stf-barrier: eieio barrier available\n");
329a048a07dSNicholas Piggin 	}
330a048a07dSNicholas Piggin 
331a048a07dSNicholas Piggin 	stf_enabled_flush_types = type;
332a048a07dSNicholas Piggin 
333782e69efSJosh Poimboeuf 	if (!no_stf_barrier && !cpu_mitigations_off())
334a048a07dSNicholas Piggin 		stf_barrier_enable(enable);
335a048a07dSNicholas Piggin }
336a048a07dSNicholas Piggin 
337a048a07dSNicholas Piggin ssize_t cpu_show_spec_store_bypass(struct device *dev, struct device_attribute *attr, char *buf)
338a048a07dSNicholas Piggin {
339a048a07dSNicholas Piggin 	if (stf_barrier && stf_enabled_flush_types != STF_BARRIER_NONE) {
340a048a07dSNicholas Piggin 		const char *type;
341a048a07dSNicholas Piggin 		switch (stf_enabled_flush_types) {
342a048a07dSNicholas Piggin 		case STF_BARRIER_EIEIO:
343a048a07dSNicholas Piggin 			type = "eieio";
344a048a07dSNicholas Piggin 			break;
345a048a07dSNicholas Piggin 		case STF_BARRIER_SYNC_ORI:
346a048a07dSNicholas Piggin 			type = "hwsync";
347a048a07dSNicholas Piggin 			break;
348a048a07dSNicholas Piggin 		case STF_BARRIER_FALLBACK:
349a048a07dSNicholas Piggin 			type = "fallback";
350a048a07dSNicholas Piggin 			break;
351a048a07dSNicholas Piggin 		default:
352a048a07dSNicholas Piggin 			type = "unknown";
353a048a07dSNicholas Piggin 		}
354a048a07dSNicholas Piggin 		return sprintf(buf, "Mitigation: Kernel entry/exit barrier (%s)\n", type);
355a048a07dSNicholas Piggin 	}
356a048a07dSNicholas Piggin 
357a048a07dSNicholas Piggin 	if (!security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) &&
358a048a07dSNicholas Piggin 	    !security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR))
359a048a07dSNicholas Piggin 		return sprintf(buf, "Not affected\n");
360a048a07dSNicholas Piggin 
361a048a07dSNicholas Piggin 	return sprintf(buf, "Vulnerable\n");
362a048a07dSNicholas Piggin }
363a048a07dSNicholas Piggin 
364d93e5e2dSMichael Ellerman static int ssb_prctl_get(struct task_struct *task)
365d93e5e2dSMichael Ellerman {
366d93e5e2dSMichael Ellerman 	if (stf_enabled_flush_types == STF_BARRIER_NONE)
367d93e5e2dSMichael Ellerman 		/*
368d93e5e2dSMichael Ellerman 		 * We don't have an explicit signal from firmware that we're
369d93e5e2dSMichael Ellerman 		 * vulnerable or not, we only have certain CPU revisions that
370d93e5e2dSMichael Ellerman 		 * are known to be vulnerable.
371d93e5e2dSMichael Ellerman 		 *
372d93e5e2dSMichael Ellerman 		 * We assume that if we're on another CPU, where the barrier is
373d93e5e2dSMichael Ellerman 		 * NONE, then we are not vulnerable.
374d93e5e2dSMichael Ellerman 		 */
375d93e5e2dSMichael Ellerman 		return PR_SPEC_NOT_AFFECTED;
376d93e5e2dSMichael Ellerman 	else
377d93e5e2dSMichael Ellerman 		/*
378d93e5e2dSMichael Ellerman 		 * If we do have a barrier type then we are vulnerable. The
379d93e5e2dSMichael Ellerman 		 * barrier is not a global or per-process mitigation, so the
380d93e5e2dSMichael Ellerman 		 * only value we can report here is PR_SPEC_ENABLE, which
381d93e5e2dSMichael Ellerman 		 * appears as "vulnerable" in /proc.
382d93e5e2dSMichael Ellerman 		 */
383d93e5e2dSMichael Ellerman 		return PR_SPEC_ENABLE;
384d93e5e2dSMichael Ellerman 
385d93e5e2dSMichael Ellerman 	return -EINVAL;
386d93e5e2dSMichael Ellerman }
387d93e5e2dSMichael Ellerman 
388d93e5e2dSMichael Ellerman int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which)
389d93e5e2dSMichael Ellerman {
390d93e5e2dSMichael Ellerman 	switch (which) {
391d93e5e2dSMichael Ellerman 	case PR_SPEC_STORE_BYPASS:
392d93e5e2dSMichael Ellerman 		return ssb_prctl_get(task);
393d93e5e2dSMichael Ellerman 	default:
394d93e5e2dSMichael Ellerman 		return -ENODEV;
395d93e5e2dSMichael Ellerman 	}
396d93e5e2dSMichael Ellerman }
397d93e5e2dSMichael Ellerman 
398a048a07dSNicholas Piggin #ifdef CONFIG_DEBUG_FS
399a048a07dSNicholas Piggin static int stf_barrier_set(void *data, u64 val)
400a048a07dSNicholas Piggin {
401a048a07dSNicholas Piggin 	bool enable;
402a048a07dSNicholas Piggin 
403a048a07dSNicholas Piggin 	if (val == 1)
404a048a07dSNicholas Piggin 		enable = true;
405a048a07dSNicholas Piggin 	else if (val == 0)
406a048a07dSNicholas Piggin 		enable = false;
407a048a07dSNicholas Piggin 	else
408a048a07dSNicholas Piggin 		return -EINVAL;
409a048a07dSNicholas Piggin 
410a048a07dSNicholas Piggin 	/* Only do anything if we're changing state */
411a048a07dSNicholas Piggin 	if (enable != stf_barrier)
412a048a07dSNicholas Piggin 		stf_barrier_enable(enable);
413a048a07dSNicholas Piggin 
414a048a07dSNicholas Piggin 	return 0;
415a048a07dSNicholas Piggin }
416a048a07dSNicholas Piggin 
417a048a07dSNicholas Piggin static int stf_barrier_get(void *data, u64 *val)
418a048a07dSNicholas Piggin {
419a048a07dSNicholas Piggin 	*val = stf_barrier ? 1 : 0;
420a048a07dSNicholas Piggin 	return 0;
421a048a07dSNicholas Piggin }
422a048a07dSNicholas Piggin 
423090d5ab9SYueHaibing DEFINE_DEBUGFS_ATTRIBUTE(fops_stf_barrier, stf_barrier_get, stf_barrier_set,
424090d5ab9SYueHaibing 			 "%llu\n");
425a048a07dSNicholas Piggin 
426a048a07dSNicholas Piggin static __init int stf_barrier_debugfs_init(void)
427a048a07dSNicholas Piggin {
428dbf77fedSAneesh Kumar K.V 	debugfs_create_file_unsafe("stf_barrier", 0600, arch_debugfs_dir,
429090d5ab9SYueHaibing 				   NULL, &fops_stf_barrier);
430a048a07dSNicholas Piggin 	return 0;
431a048a07dSNicholas Piggin }
432a048a07dSNicholas Piggin device_initcall(stf_barrier_debugfs_init);
433a048a07dSNicholas Piggin #endif /* CONFIG_DEBUG_FS */
434ee13cb24SMichael Ellerman 
435c0036549SNicholas Piggin static void update_branch_cache_flush(void)
436ee13cb24SMichael Ellerman {
43789d35b23SNicholas Piggin 	u32 *site, __maybe_unused *site2;
438792254a7SNicholas Piggin 
439c0036549SNicholas Piggin #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
440792254a7SNicholas Piggin 	site = &patch__call_kvm_flush_link_stack;
44189d35b23SNicholas Piggin 	site2 = &patch__call_kvm_flush_link_stack_p9;
442c0036549SNicholas Piggin 	// This controls the branch from guest_exit_cont to kvm_flush_link_stack
443c0036549SNicholas Piggin 	if (link_stack_flush_type == BRANCH_CACHE_FLUSH_NONE) {
444e7304597SChristophe Leroy 		patch_instruction_site(site, ppc_inst(PPC_RAW_NOP()));
4453c536423SMichael Ellerman 		patch_instruction_site(site2, ppc_inst(PPC_RAW_NOP()));
446c0036549SNicholas Piggin 	} else {
4474d24e21cSNicholas Piggin 		// Could use HW flush, but that could also flush count cache
448792254a7SNicholas Piggin 		patch_branch_site(site, (u64)&kvm_flush_link_stack, BRANCH_SET_LINK);
44989d35b23SNicholas Piggin 		patch_branch_site(site2, (u64)&kvm_flush_link_stack, BRANCH_SET_LINK);
450c0036549SNicholas Piggin 	}
451c0036549SNicholas Piggin #endif
452c0036549SNicholas Piggin 
453792254a7SNicholas Piggin 	// Patch out the bcctr first, then nop the rest
454792254a7SNicholas Piggin 	site = &patch__call_flush_branch_caches3;
455e7304597SChristophe Leroy 	patch_instruction_site(site, ppc_inst(PPC_RAW_NOP()));
456792254a7SNicholas Piggin 	site = &patch__call_flush_branch_caches2;
457e7304597SChristophe Leroy 	patch_instruction_site(site, ppc_inst(PPC_RAW_NOP()));
458792254a7SNicholas Piggin 	site = &patch__call_flush_branch_caches1;
459e7304597SChristophe Leroy 	patch_instruction_site(site, ppc_inst(PPC_RAW_NOP()));
460792254a7SNicholas Piggin 
461c0036549SNicholas Piggin 	// This controls the branch from _switch to flush_branch_caches
462c0036549SNicholas Piggin 	if (count_cache_flush_type == BRANCH_CACHE_FLUSH_NONE &&
463c0036549SNicholas Piggin 	    link_stack_flush_type == BRANCH_CACHE_FLUSH_NONE) {
464792254a7SNicholas Piggin 		// Nothing to be done
465792254a7SNicholas Piggin 
4664d24e21cSNicholas Piggin 	} else if (count_cache_flush_type == BRANCH_CACHE_FLUSH_HW &&
4674d24e21cSNicholas Piggin 		   link_stack_flush_type == BRANCH_CACHE_FLUSH_HW) {
468792254a7SNicholas Piggin 		// Patch in the bcctr last
469792254a7SNicholas Piggin 		site = &patch__call_flush_branch_caches1;
470792254a7SNicholas Piggin 		patch_instruction_site(site, ppc_inst(0x39207fff)); // li r9,0x7fff
471792254a7SNicholas Piggin 		site = &patch__call_flush_branch_caches2;
472792254a7SNicholas Piggin 		patch_instruction_site(site, ppc_inst(0x7d2903a6)); // mtctr r9
473792254a7SNicholas Piggin 		site = &patch__call_flush_branch_caches3;
474792254a7SNicholas Piggin 		patch_instruction_site(site, ppc_inst(PPC_INST_BCCTR_FLUSH));
475792254a7SNicholas Piggin 
476c0036549SNicholas Piggin 	} else {
477792254a7SNicholas Piggin 		patch_branch_site(site, (u64)&flush_branch_caches, BRANCH_SET_LINK);
478c0036549SNicholas Piggin 
479c0036549SNicholas Piggin 		// If we just need to flush the link stack, early return
480c0036549SNicholas Piggin 		if (count_cache_flush_type == BRANCH_CACHE_FLUSH_NONE) {
481c0036549SNicholas Piggin 			patch_instruction_site(&patch__flush_link_stack_return,
482e7304597SChristophe Leroy 					       ppc_inst(PPC_RAW_BLR()));
483c0036549SNicholas Piggin 
484c0036549SNicholas Piggin 		// If we have flush instruction, early return
485c0036549SNicholas Piggin 		} else if (count_cache_flush_type == BRANCH_CACHE_FLUSH_HW) {
486c0036549SNicholas Piggin 			patch_instruction_site(&patch__flush_count_cache_return,
487e7304597SChristophe Leroy 					       ppc_inst(PPC_RAW_BLR()));
488c0036549SNicholas Piggin 		}
489c0036549SNicholas Piggin 	}
49039e72bf9SMichael Ellerman }
49139e72bf9SMichael Ellerman 
4921026798cSNicholas Piggin static void toggle_branch_cache_flush(bool enable)
49339e72bf9SMichael Ellerman {
494c0036549SNicholas Piggin 	if (!enable || !security_ftr_enabled(SEC_FTR_FLUSH_COUNT_CACHE)) {
495c0036549SNicholas Piggin 		if (count_cache_flush_type != BRANCH_CACHE_FLUSH_NONE)
496c0036549SNicholas Piggin 			count_cache_flush_type = BRANCH_CACHE_FLUSH_NONE;
49739e72bf9SMichael Ellerman 
498c0036549SNicholas Piggin 		pr_info("count-cache-flush: flush disabled.\n");
499c0036549SNicholas Piggin 	} else {
500c0036549SNicholas Piggin 		if (security_ftr_enabled(SEC_FTR_BCCTR_FLUSH_ASSIST)) {
5011026798cSNicholas Piggin 			count_cache_flush_type = BRANCH_CACHE_FLUSH_HW;
5021afe00c7SNicholas Piggin 			pr_info("count-cache-flush: hardware flush enabled.\n");
503c0036549SNicholas Piggin 		} else {
504c0036549SNicholas Piggin 			count_cache_flush_type = BRANCH_CACHE_FLUSH_SW;
505c0036549SNicholas Piggin 			pr_info("count-cache-flush: software flush enabled.\n");
506c0036549SNicholas Piggin 		}
507c0036549SNicholas Piggin 	}
508c0036549SNicholas Piggin 
509c0036549SNicholas Piggin 	if (!enable || !security_ftr_enabled(SEC_FTR_FLUSH_LINK_STACK)) {
510c0036549SNicholas Piggin 		if (link_stack_flush_type != BRANCH_CACHE_FLUSH_NONE)
511c0036549SNicholas Piggin 			link_stack_flush_type = BRANCH_CACHE_FLUSH_NONE;
512c0036549SNicholas Piggin 
513c0036549SNicholas Piggin 		pr_info("link-stack-flush: flush disabled.\n");
514c0036549SNicholas Piggin 	} else {
5154d24e21cSNicholas Piggin 		if (security_ftr_enabled(SEC_FTR_BCCTR_LINK_FLUSH_ASSIST)) {
5164d24e21cSNicholas Piggin 			link_stack_flush_type = BRANCH_CACHE_FLUSH_HW;
5174d24e21cSNicholas Piggin 			pr_info("link-stack-flush: hardware flush enabled.\n");
5184d24e21cSNicholas Piggin 		} else {
519c0036549SNicholas Piggin 			link_stack_flush_type = BRANCH_CACHE_FLUSH_SW;
520c0036549SNicholas Piggin 			pr_info("link-stack-flush: software flush enabled.\n");
521c0036549SNicholas Piggin 		}
5224d24e21cSNicholas Piggin 	}
523c0036549SNicholas Piggin 
524c0036549SNicholas Piggin 	update_branch_cache_flush();
525ee13cb24SMichael Ellerman }
526ee13cb24SMichael Ellerman 
527ee13cb24SMichael Ellerman void setup_count_cache_flush(void)
528ee13cb24SMichael Ellerman {
529d8f0e0b0SChristopher M. Riedl 	bool enable = true;
530d8f0e0b0SChristopher M. Riedl 
531d8f0e0b0SChristopher M. Riedl 	if (no_spectrev2 || cpu_mitigations_off()) {
532d8f0e0b0SChristopher M. Riedl 		if (security_ftr_enabled(SEC_FTR_BCCTRL_SERIALISED) ||
533d8f0e0b0SChristopher M. Riedl 		    security_ftr_enabled(SEC_FTR_COUNT_CACHE_DISABLED))
53439e72bf9SMichael Ellerman 			pr_warn("Spectre v2 mitigations not fully under software control, can't disable\n");
535d8f0e0b0SChristopher M. Riedl 
536d8f0e0b0SChristopher M. Riedl 		enable = false;
537d8f0e0b0SChristopher M. Riedl 	}
538d8f0e0b0SChristopher M. Riedl 
53939e72bf9SMichael Ellerman 	/*
54039e72bf9SMichael Ellerman 	 * There's no firmware feature flag/hypervisor bit to tell us we need to
54139e72bf9SMichael Ellerman 	 * flush the link stack on context switch. So we set it here if we see
54239e72bf9SMichael Ellerman 	 * either of the Spectre v2 mitigations that aim to protect userspace.
54339e72bf9SMichael Ellerman 	 */
54439e72bf9SMichael Ellerman 	if (security_ftr_enabled(SEC_FTR_COUNT_CACHE_DISABLED) ||
54539e72bf9SMichael Ellerman 	    security_ftr_enabled(SEC_FTR_FLUSH_COUNT_CACHE))
54639e72bf9SMichael Ellerman 		security_ftr_set(SEC_FTR_FLUSH_LINK_STACK);
54739e72bf9SMichael Ellerman 
5481026798cSNicholas Piggin 	toggle_branch_cache_flush(enable);
549ee13cb24SMichael Ellerman }
550ee13cb24SMichael Ellerman 
551c6b4c914SMichael Ellerman static enum l1d_flush_type enabled_flush_types;
552c6b4c914SMichael Ellerman static void *l1d_flush_fallback_area;
553c6b4c914SMichael Ellerman static bool no_rfi_flush;
554c6b4c914SMichael Ellerman static bool no_entry_flush;
555c6b4c914SMichael Ellerman static bool no_uaccess_flush;
556c6b4c914SMichael Ellerman bool rfi_flush;
557c6b4c914SMichael Ellerman static bool entry_flush;
558c6b4c914SMichael Ellerman static bool uaccess_flush;
559c6b4c914SMichael Ellerman DEFINE_STATIC_KEY_FALSE(uaccess_flush_key);
560c6b4c914SMichael Ellerman EXPORT_SYMBOL(uaccess_flush_key);
561c6b4c914SMichael Ellerman 
562c6b4c914SMichael Ellerman static int __init handle_no_rfi_flush(char *p)
563c6b4c914SMichael Ellerman {
564c6b4c914SMichael Ellerman 	pr_info("rfi-flush: disabled on command line.");
565c6b4c914SMichael Ellerman 	no_rfi_flush = true;
566c6b4c914SMichael Ellerman 	return 0;
567c6b4c914SMichael Ellerman }
568c6b4c914SMichael Ellerman early_param("no_rfi_flush", handle_no_rfi_flush);
569c6b4c914SMichael Ellerman 
570c6b4c914SMichael Ellerman static int __init handle_no_entry_flush(char *p)
571c6b4c914SMichael Ellerman {
572c6b4c914SMichael Ellerman 	pr_info("entry-flush: disabled on command line.");
573c6b4c914SMichael Ellerman 	no_entry_flush = true;
574c6b4c914SMichael Ellerman 	return 0;
575c6b4c914SMichael Ellerman }
576c6b4c914SMichael Ellerman early_param("no_entry_flush", handle_no_entry_flush);
577c6b4c914SMichael Ellerman 
578c6b4c914SMichael Ellerman static int __init handle_no_uaccess_flush(char *p)
579c6b4c914SMichael Ellerman {
580c6b4c914SMichael Ellerman 	pr_info("uaccess-flush: disabled on command line.");
581c6b4c914SMichael Ellerman 	no_uaccess_flush = true;
582c6b4c914SMichael Ellerman 	return 0;
583c6b4c914SMichael Ellerman }
584c6b4c914SMichael Ellerman early_param("no_uaccess_flush", handle_no_uaccess_flush);
585c6b4c914SMichael Ellerman 
586c6b4c914SMichael Ellerman /*
587c6b4c914SMichael Ellerman  * The RFI flush is not KPTI, but because users will see doco that says to use
588c6b4c914SMichael Ellerman  * nopti we hijack that option here to also disable the RFI flush.
589c6b4c914SMichael Ellerman  */
590c6b4c914SMichael Ellerman static int __init handle_no_pti(char *p)
591c6b4c914SMichael Ellerman {
592c6b4c914SMichael Ellerman 	pr_info("rfi-flush: disabling due to 'nopti' on command line.\n");
593c6b4c914SMichael Ellerman 	handle_no_rfi_flush(NULL);
594c6b4c914SMichael Ellerman 	return 0;
595c6b4c914SMichael Ellerman }
596c6b4c914SMichael Ellerman early_param("nopti", handle_no_pti);
597c6b4c914SMichael Ellerman 
598c6b4c914SMichael Ellerman static void do_nothing(void *unused)
599c6b4c914SMichael Ellerman {
600c6b4c914SMichael Ellerman 	/*
601c6b4c914SMichael Ellerman 	 * We don't need to do the flush explicitly, just enter+exit kernel is
602c6b4c914SMichael Ellerman 	 * sufficient, the RFI exit handlers will do the right thing.
603c6b4c914SMichael Ellerman 	 */
604c6b4c914SMichael Ellerman }
605c6b4c914SMichael Ellerman 
606c6b4c914SMichael Ellerman void rfi_flush_enable(bool enable)
607c6b4c914SMichael Ellerman {
608c6b4c914SMichael Ellerman 	if (enable) {
609c6b4c914SMichael Ellerman 		do_rfi_flush_fixups(enabled_flush_types);
610c6b4c914SMichael Ellerman 		on_each_cpu(do_nothing, NULL, 1);
611c6b4c914SMichael Ellerman 	} else
612c6b4c914SMichael Ellerman 		do_rfi_flush_fixups(L1D_FLUSH_NONE);
613c6b4c914SMichael Ellerman 
614c6b4c914SMichael Ellerman 	rfi_flush = enable;
615c6b4c914SMichael Ellerman }
616c6b4c914SMichael Ellerman 
617c6b4c914SMichael Ellerman static void entry_flush_enable(bool enable)
618c6b4c914SMichael Ellerman {
619c6b4c914SMichael Ellerman 	if (enable) {
620c6b4c914SMichael Ellerman 		do_entry_flush_fixups(enabled_flush_types);
621c6b4c914SMichael Ellerman 		on_each_cpu(do_nothing, NULL, 1);
622c6b4c914SMichael Ellerman 	} else {
623c6b4c914SMichael Ellerman 		do_entry_flush_fixups(L1D_FLUSH_NONE);
624c6b4c914SMichael Ellerman 	}
625c6b4c914SMichael Ellerman 
626c6b4c914SMichael Ellerman 	entry_flush = enable;
627c6b4c914SMichael Ellerman }
628c6b4c914SMichael Ellerman 
629c6b4c914SMichael Ellerman static void uaccess_flush_enable(bool enable)
630c6b4c914SMichael Ellerman {
631c6b4c914SMichael Ellerman 	if (enable) {
632c6b4c914SMichael Ellerman 		do_uaccess_flush_fixups(enabled_flush_types);
633c6b4c914SMichael Ellerman 		static_branch_enable(&uaccess_flush_key);
634c6b4c914SMichael Ellerman 		on_each_cpu(do_nothing, NULL, 1);
635c6b4c914SMichael Ellerman 	} else {
636c6b4c914SMichael Ellerman 		static_branch_disable(&uaccess_flush_key);
637c6b4c914SMichael Ellerman 		do_uaccess_flush_fixups(L1D_FLUSH_NONE);
638c6b4c914SMichael Ellerman 	}
639c6b4c914SMichael Ellerman 
640c6b4c914SMichael Ellerman 	uaccess_flush = enable;
641c6b4c914SMichael Ellerman }
642c6b4c914SMichael Ellerman 
643c6b4c914SMichael Ellerman static void __ref init_fallback_flush(void)
644c6b4c914SMichael Ellerman {
645c6b4c914SMichael Ellerman 	u64 l1d_size, limit;
646c6b4c914SMichael Ellerman 	int cpu;
647c6b4c914SMichael Ellerman 
648c6b4c914SMichael Ellerman 	/* Only allocate the fallback flush area once (at boot time). */
649c6b4c914SMichael Ellerman 	if (l1d_flush_fallback_area)
650c6b4c914SMichael Ellerman 		return;
651c6b4c914SMichael Ellerman 
652c6b4c914SMichael Ellerman 	l1d_size = ppc64_caches.l1d.size;
653c6b4c914SMichael Ellerman 
654c6b4c914SMichael Ellerman 	/*
655c6b4c914SMichael Ellerman 	 * If there is no d-cache-size property in the device tree, l1d_size
656c6b4c914SMichael Ellerman 	 * could be zero. That leads to the loop in the asm wrapping around to
657c6b4c914SMichael Ellerman 	 * 2^64-1, and then walking off the end of the fallback area and
658c6b4c914SMichael Ellerman 	 * eventually causing a page fault which is fatal. Just default to
659c6b4c914SMichael Ellerman 	 * something vaguely sane.
660c6b4c914SMichael Ellerman 	 */
661c6b4c914SMichael Ellerman 	if (!l1d_size)
662c6b4c914SMichael Ellerman 		l1d_size = (64 * 1024);
663c6b4c914SMichael Ellerman 
664c6b4c914SMichael Ellerman 	limit = min(ppc64_bolted_size(), ppc64_rma_size);
665c6b4c914SMichael Ellerman 
666c6b4c914SMichael Ellerman 	/*
667c6b4c914SMichael Ellerman 	 * Align to L1d size, and size it at 2x L1d size, to catch possible
668c6b4c914SMichael Ellerman 	 * hardware prefetch runoff. We don't have a recipe for load patterns to
669c6b4c914SMichael Ellerman 	 * reliably avoid the prefetcher.
670c6b4c914SMichael Ellerman 	 */
671c6b4c914SMichael Ellerman 	l1d_flush_fallback_area = memblock_alloc_try_nid(l1d_size * 2,
672c6b4c914SMichael Ellerman 						l1d_size, MEMBLOCK_LOW_LIMIT,
673c6b4c914SMichael Ellerman 						limit, NUMA_NO_NODE);
674c6b4c914SMichael Ellerman 	if (!l1d_flush_fallback_area)
675c6b4c914SMichael Ellerman 		panic("%s: Failed to allocate %llu bytes align=0x%llx max_addr=%pa\n",
676c6b4c914SMichael Ellerman 		      __func__, l1d_size * 2, l1d_size, &limit);
677c6b4c914SMichael Ellerman 
678c6b4c914SMichael Ellerman 
679c6b4c914SMichael Ellerman 	for_each_possible_cpu(cpu) {
680c6b4c914SMichael Ellerman 		struct paca_struct *paca = paca_ptrs[cpu];
681c6b4c914SMichael Ellerman 		paca->rfi_flush_fallback_area = l1d_flush_fallback_area;
682c6b4c914SMichael Ellerman 		paca->l1d_flush_size = l1d_size;
683c6b4c914SMichael Ellerman 	}
684c6b4c914SMichael Ellerman }
685c6b4c914SMichael Ellerman 
686c6b4c914SMichael Ellerman void setup_rfi_flush(enum l1d_flush_type types, bool enable)
687c6b4c914SMichael Ellerman {
688c6b4c914SMichael Ellerman 	if (types & L1D_FLUSH_FALLBACK) {
689c6b4c914SMichael Ellerman 		pr_info("rfi-flush: fallback displacement flush available\n");
690c6b4c914SMichael Ellerman 		init_fallback_flush();
691c6b4c914SMichael Ellerman 	}
692c6b4c914SMichael Ellerman 
693c6b4c914SMichael Ellerman 	if (types & L1D_FLUSH_ORI)
694c6b4c914SMichael Ellerman 		pr_info("rfi-flush: ori type flush available\n");
695c6b4c914SMichael Ellerman 
696c6b4c914SMichael Ellerman 	if (types & L1D_FLUSH_MTTRIG)
697c6b4c914SMichael Ellerman 		pr_info("rfi-flush: mttrig type flush available\n");
698c6b4c914SMichael Ellerman 
699c6b4c914SMichael Ellerman 	enabled_flush_types = types;
700c6b4c914SMichael Ellerman 
701c6b4c914SMichael Ellerman 	if (!cpu_mitigations_off() && !no_rfi_flush)
702c6b4c914SMichael Ellerman 		rfi_flush_enable(enable);
703c6b4c914SMichael Ellerman }
704c6b4c914SMichael Ellerman 
705c6b4c914SMichael Ellerman void setup_entry_flush(bool enable)
706c6b4c914SMichael Ellerman {
707c6b4c914SMichael Ellerman 	if (cpu_mitigations_off())
708c6b4c914SMichael Ellerman 		return;
709c6b4c914SMichael Ellerman 
710c6b4c914SMichael Ellerman 	if (!no_entry_flush)
711c6b4c914SMichael Ellerman 		entry_flush_enable(enable);
712c6b4c914SMichael Ellerman }
713c6b4c914SMichael Ellerman 
714c6b4c914SMichael Ellerman void setup_uaccess_flush(bool enable)
715c6b4c914SMichael Ellerman {
716c6b4c914SMichael Ellerman 	if (cpu_mitigations_off())
717c6b4c914SMichael Ellerman 		return;
718c6b4c914SMichael Ellerman 
719c6b4c914SMichael Ellerman 	if (!no_uaccess_flush)
720c6b4c914SMichael Ellerman 		uaccess_flush_enable(enable);
721c6b4c914SMichael Ellerman }
722c6b4c914SMichael Ellerman 
723ee13cb24SMichael Ellerman #ifdef CONFIG_DEBUG_FS
724ee13cb24SMichael Ellerman static int count_cache_flush_set(void *data, u64 val)
725ee13cb24SMichael Ellerman {
726ee13cb24SMichael Ellerman 	bool enable;
727ee13cb24SMichael Ellerman 
728ee13cb24SMichael Ellerman 	if (val == 1)
729ee13cb24SMichael Ellerman 		enable = true;
730ee13cb24SMichael Ellerman 	else if (val == 0)
731ee13cb24SMichael Ellerman 		enable = false;
732ee13cb24SMichael Ellerman 	else
733ee13cb24SMichael Ellerman 		return -EINVAL;
734ee13cb24SMichael Ellerman 
7351026798cSNicholas Piggin 	toggle_branch_cache_flush(enable);
736ee13cb24SMichael Ellerman 
737ee13cb24SMichael Ellerman 	return 0;
738ee13cb24SMichael Ellerman }
739ee13cb24SMichael Ellerman 
740ee13cb24SMichael Ellerman static int count_cache_flush_get(void *data, u64 *val)
741ee13cb24SMichael Ellerman {
7421026798cSNicholas Piggin 	if (count_cache_flush_type == BRANCH_CACHE_FLUSH_NONE)
743ee13cb24SMichael Ellerman 		*val = 0;
744ee13cb24SMichael Ellerman 	else
745ee13cb24SMichael Ellerman 		*val = 1;
746ee13cb24SMichael Ellerman 
747ee13cb24SMichael Ellerman 	return 0;
748ee13cb24SMichael Ellerman }
749ee13cb24SMichael Ellerman 
750*b2a6f604SMichal Suchanek static int link_stack_flush_get(void *data, u64 *val)
751*b2a6f604SMichal Suchanek {
752*b2a6f604SMichal Suchanek 	if (link_stack_flush_type == BRANCH_CACHE_FLUSH_NONE)
753*b2a6f604SMichal Suchanek 		*val = 0;
754*b2a6f604SMichal Suchanek 	else
755*b2a6f604SMichal Suchanek 		*val = 1;
756*b2a6f604SMichal Suchanek 
757*b2a6f604SMichal Suchanek 	return 0;
758*b2a6f604SMichal Suchanek }
759*b2a6f604SMichal Suchanek 
760090d5ab9SYueHaibing DEFINE_DEBUGFS_ATTRIBUTE(fops_count_cache_flush, count_cache_flush_get,
761ee13cb24SMichael Ellerman 			 count_cache_flush_set, "%llu\n");
762*b2a6f604SMichal Suchanek DEFINE_DEBUGFS_ATTRIBUTE(fops_link_stack_flush, link_stack_flush_get,
763*b2a6f604SMichal Suchanek 			 count_cache_flush_set, "%llu\n");
764ee13cb24SMichael Ellerman 
765ee13cb24SMichael Ellerman static __init int count_cache_flush_debugfs_init(void)
766ee13cb24SMichael Ellerman {
767090d5ab9SYueHaibing 	debugfs_create_file_unsafe("count_cache_flush", 0600,
768dbf77fedSAneesh Kumar K.V 				   arch_debugfs_dir, NULL,
769090d5ab9SYueHaibing 				   &fops_count_cache_flush);
770*b2a6f604SMichal Suchanek 	debugfs_create_file_unsafe("link_stack_flush", 0600,
771*b2a6f604SMichal Suchanek 				   arch_debugfs_dir, NULL,
772*b2a6f604SMichal Suchanek 				   &fops_link_stack_flush);
773ee13cb24SMichael Ellerman 	return 0;
774ee13cb24SMichael Ellerman }
775ee13cb24SMichael Ellerman device_initcall(count_cache_flush_debugfs_init);
776c6b4c914SMichael Ellerman 
777c6b4c914SMichael Ellerman static int rfi_flush_set(void *data, u64 val)
778c6b4c914SMichael Ellerman {
779c6b4c914SMichael Ellerman 	bool enable;
780c6b4c914SMichael Ellerman 
781c6b4c914SMichael Ellerman 	if (val == 1)
782c6b4c914SMichael Ellerman 		enable = true;
783c6b4c914SMichael Ellerman 	else if (val == 0)
784c6b4c914SMichael Ellerman 		enable = false;
785c6b4c914SMichael Ellerman 	else
786c6b4c914SMichael Ellerman 		return -EINVAL;
787c6b4c914SMichael Ellerman 
788c6b4c914SMichael Ellerman 	/* Only do anything if we're changing state */
789c6b4c914SMichael Ellerman 	if (enable != rfi_flush)
790c6b4c914SMichael Ellerman 		rfi_flush_enable(enable);
791c6b4c914SMichael Ellerman 
792c6b4c914SMichael Ellerman 	return 0;
793c6b4c914SMichael Ellerman }
794c6b4c914SMichael Ellerman 
795c6b4c914SMichael Ellerman static int rfi_flush_get(void *data, u64 *val)
796c6b4c914SMichael Ellerman {
797c6b4c914SMichael Ellerman 	*val = rfi_flush ? 1 : 0;
798c6b4c914SMichael Ellerman 	return 0;
799c6b4c914SMichael Ellerman }
800c6b4c914SMichael Ellerman 
801c6b4c914SMichael Ellerman DEFINE_SIMPLE_ATTRIBUTE(fops_rfi_flush, rfi_flush_get, rfi_flush_set, "%llu\n");
802c6b4c914SMichael Ellerman 
803c6b4c914SMichael Ellerman static int entry_flush_set(void *data, u64 val)
804c6b4c914SMichael Ellerman {
805c6b4c914SMichael Ellerman 	bool enable;
806c6b4c914SMichael Ellerman 
807c6b4c914SMichael Ellerman 	if (val == 1)
808c6b4c914SMichael Ellerman 		enable = true;
809c6b4c914SMichael Ellerman 	else if (val == 0)
810c6b4c914SMichael Ellerman 		enable = false;
811c6b4c914SMichael Ellerman 	else
812c6b4c914SMichael Ellerman 		return -EINVAL;
813c6b4c914SMichael Ellerman 
814c6b4c914SMichael Ellerman 	/* Only do anything if we're changing state */
815c6b4c914SMichael Ellerman 	if (enable != entry_flush)
816c6b4c914SMichael Ellerman 		entry_flush_enable(enable);
817c6b4c914SMichael Ellerman 
818c6b4c914SMichael Ellerman 	return 0;
819c6b4c914SMichael Ellerman }
820c6b4c914SMichael Ellerman 
821c6b4c914SMichael Ellerman static int entry_flush_get(void *data, u64 *val)
822c6b4c914SMichael Ellerman {
823c6b4c914SMichael Ellerman 	*val = entry_flush ? 1 : 0;
824c6b4c914SMichael Ellerman 	return 0;
825c6b4c914SMichael Ellerman }
826c6b4c914SMichael Ellerman 
827c6b4c914SMichael Ellerman DEFINE_SIMPLE_ATTRIBUTE(fops_entry_flush, entry_flush_get, entry_flush_set, "%llu\n");
828c6b4c914SMichael Ellerman 
829c6b4c914SMichael Ellerman static int uaccess_flush_set(void *data, u64 val)
830c6b4c914SMichael Ellerman {
831c6b4c914SMichael Ellerman 	bool enable;
832c6b4c914SMichael Ellerman 
833c6b4c914SMichael Ellerman 	if (val == 1)
834c6b4c914SMichael Ellerman 		enable = true;
835c6b4c914SMichael Ellerman 	else if (val == 0)
836c6b4c914SMichael Ellerman 		enable = false;
837c6b4c914SMichael Ellerman 	else
838c6b4c914SMichael Ellerman 		return -EINVAL;
839c6b4c914SMichael Ellerman 
840c6b4c914SMichael Ellerman 	/* Only do anything if we're changing state */
841c6b4c914SMichael Ellerman 	if (enable != uaccess_flush)
842c6b4c914SMichael Ellerman 		uaccess_flush_enable(enable);
843c6b4c914SMichael Ellerman 
844c6b4c914SMichael Ellerman 	return 0;
845c6b4c914SMichael Ellerman }
846c6b4c914SMichael Ellerman 
847c6b4c914SMichael Ellerman static int uaccess_flush_get(void *data, u64 *val)
848c6b4c914SMichael Ellerman {
849c6b4c914SMichael Ellerman 	*val = uaccess_flush ? 1 : 0;
850c6b4c914SMichael Ellerman 	return 0;
851c6b4c914SMichael Ellerman }
852c6b4c914SMichael Ellerman 
853c6b4c914SMichael Ellerman DEFINE_SIMPLE_ATTRIBUTE(fops_uaccess_flush, uaccess_flush_get, uaccess_flush_set, "%llu\n");
854c6b4c914SMichael Ellerman 
855c6b4c914SMichael Ellerman static __init int rfi_flush_debugfs_init(void)
856c6b4c914SMichael Ellerman {
857dbf77fedSAneesh Kumar K.V 	debugfs_create_file("rfi_flush", 0600, arch_debugfs_dir, NULL, &fops_rfi_flush);
858dbf77fedSAneesh Kumar K.V 	debugfs_create_file("entry_flush", 0600, arch_debugfs_dir, NULL, &fops_entry_flush);
859dbf77fedSAneesh Kumar K.V 	debugfs_create_file("uaccess_flush", 0600, arch_debugfs_dir, NULL, &fops_uaccess_flush);
860c6b4c914SMichael Ellerman 	return 0;
861c6b4c914SMichael Ellerman }
862c6b4c914SMichael Ellerman device_initcall(rfi_flush_debugfs_init);
863ee13cb24SMichael Ellerman #endif /* CONFIG_DEBUG_FS */
8646453b532SDiana Craciun #endif /* CONFIG_PPC_BOOK3S_64 */
865