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> 10ff348355SMichael Ellerman #include <linux/seq_buf.h> 118ad33041SMichael Ellerman 12ee13cb24SMichael Ellerman #include <asm/asm-prototypes.h> 13ee13cb24SMichael Ellerman #include <asm/code-patching.h> 14a048a07dSNicholas Piggin #include <asm/debugfs.h> 159a868f63SMichael Ellerman #include <asm/security_features.h> 162eea7f06SMichal Suchanek #include <asm/setup.h> 179a868f63SMichael Ellerman 189a868f63SMichael Ellerman 19e7347a86SMauricio Faria de Oliveira unsigned long powerpc_security_features __read_mostly = SEC_FTR_DEFAULT; 208ad33041SMichael Ellerman 21ee13cb24SMichael Ellerman enum count_cache_flush_type { 22ee13cb24SMichael Ellerman COUNT_CACHE_FLUSH_NONE = 0x1, 23ee13cb24SMichael Ellerman COUNT_CACHE_FLUSH_SW = 0x2, 24ee13cb24SMichael Ellerman COUNT_CACHE_FLUSH_HW = 0x4, 25ee13cb24SMichael Ellerman }; 267d8bad99SDiana Craciun static enum count_cache_flush_type count_cache_flush_type = COUNT_CACHE_FLUSH_NONE; 2739e72bf9SMichael Ellerman static bool link_stack_flush_enabled; 28ee13cb24SMichael Ellerman 29815069caSMichal Suchanek bool barrier_nospec_enabled; 30cf175dc3SDiana Craciun static bool no_nospec; 31f633a8adSDiana Craciun static bool btb_flush_enabled; 32d8f0e0b0SChristopher M. Riedl #if defined(CONFIG_PPC_FSL_BOOK3E) || defined(CONFIG_PPC_BOOK3S_64) 33f633a8adSDiana Craciun static bool no_spectrev2; 34f633a8adSDiana Craciun #endif 352eea7f06SMichal Suchanek 362eea7f06SMichal Suchanek static void enable_barrier_nospec(bool enable) 372eea7f06SMichal Suchanek { 382eea7f06SMichal Suchanek barrier_nospec_enabled = enable; 392eea7f06SMichal Suchanek do_barrier_nospec_fixups(enable); 402eea7f06SMichal Suchanek } 412eea7f06SMichal Suchanek 42cb3d6759SMichal Suchanek void setup_barrier_nospec(void) 43cb3d6759SMichal Suchanek { 44cb3d6759SMichal Suchanek bool enable; 45cb3d6759SMichal Suchanek 46cb3d6759SMichal Suchanek /* 47cb3d6759SMichal Suchanek * It would make sense to check SEC_FTR_SPEC_BAR_ORI31 below as well. 48cb3d6759SMichal Suchanek * But there's a good reason not to. The two flags we check below are 49cb3d6759SMichal Suchanek * both are enabled by default in the kernel, so if the hcall is not 50cb3d6759SMichal Suchanek * functional they will be enabled. 51cb3d6759SMichal Suchanek * On a system where the host firmware has been updated (so the ori 52cb3d6759SMichal Suchanek * functions as a barrier), but on which the hypervisor (KVM/Qemu) has 53cb3d6759SMichal Suchanek * not been updated, we would like to enable the barrier. Dropping the 54cb3d6759SMichal Suchanek * check for SEC_FTR_SPEC_BAR_ORI31 achieves that. The only downside is 55cb3d6759SMichal Suchanek * we potentially enable the barrier on systems where the host firmware 56cb3d6759SMichal Suchanek * is not updated, but that's harmless as it's a no-op. 57cb3d6759SMichal Suchanek */ 58cb3d6759SMichal Suchanek enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) && 59cb3d6759SMichal Suchanek security_ftr_enabled(SEC_FTR_BNDS_CHK_SPEC_BAR); 60cb3d6759SMichal Suchanek 61782e69efSJosh Poimboeuf if (!no_nospec && !cpu_mitigations_off()) 62cb3d6759SMichal Suchanek enable_barrier_nospec(enable); 63cb3d6759SMichal Suchanek } 64cb3d6759SMichal Suchanek 65cf175dc3SDiana Craciun static int __init handle_nospectre_v1(char *p) 66cf175dc3SDiana Craciun { 67cf175dc3SDiana Craciun no_nospec = true; 68cf175dc3SDiana Craciun 69cf175dc3SDiana Craciun return 0; 70cf175dc3SDiana Craciun } 71cf175dc3SDiana Craciun early_param("nospectre_v1", handle_nospectre_v1); 72cf175dc3SDiana Craciun 73cb3d6759SMichal Suchanek #ifdef CONFIG_DEBUG_FS 74cb3d6759SMichal Suchanek static int barrier_nospec_set(void *data, u64 val) 75cb3d6759SMichal Suchanek { 76cb3d6759SMichal Suchanek switch (val) { 77cb3d6759SMichal Suchanek case 0: 78cb3d6759SMichal Suchanek case 1: 79cb3d6759SMichal Suchanek break; 80cb3d6759SMichal Suchanek default: 81cb3d6759SMichal Suchanek return -EINVAL; 82cb3d6759SMichal Suchanek } 83cb3d6759SMichal Suchanek 84cb3d6759SMichal Suchanek if (!!val == !!barrier_nospec_enabled) 85cb3d6759SMichal Suchanek return 0; 86cb3d6759SMichal Suchanek 87cb3d6759SMichal Suchanek enable_barrier_nospec(!!val); 88cb3d6759SMichal Suchanek 89cb3d6759SMichal Suchanek return 0; 90cb3d6759SMichal Suchanek } 91cb3d6759SMichal Suchanek 92cb3d6759SMichal Suchanek static int barrier_nospec_get(void *data, u64 *val) 93cb3d6759SMichal Suchanek { 94cb3d6759SMichal Suchanek *val = barrier_nospec_enabled ? 1 : 0; 95cb3d6759SMichal Suchanek return 0; 96cb3d6759SMichal Suchanek } 97cb3d6759SMichal Suchanek 98cb3d6759SMichal Suchanek DEFINE_SIMPLE_ATTRIBUTE(fops_barrier_nospec, 99cb3d6759SMichal Suchanek barrier_nospec_get, barrier_nospec_set, "%llu\n"); 100cb3d6759SMichal Suchanek 101cb3d6759SMichal Suchanek static __init int barrier_nospec_debugfs_init(void) 102cb3d6759SMichal Suchanek { 103cb3d6759SMichal Suchanek debugfs_create_file("barrier_nospec", 0600, powerpc_debugfs_root, NULL, 104cb3d6759SMichal Suchanek &fops_barrier_nospec); 105cb3d6759SMichal Suchanek return 0; 106cb3d6759SMichal Suchanek } 107cb3d6759SMichal Suchanek device_initcall(barrier_nospec_debugfs_init); 108398af571SMichael Ellerman 109398af571SMichael Ellerman static __init int security_feature_debugfs_init(void) 110398af571SMichael Ellerman { 111398af571SMichael Ellerman debugfs_create_x64("security_features", 0400, powerpc_debugfs_root, 112398af571SMichael Ellerman (u64 *)&powerpc_security_features); 113398af571SMichael Ellerman return 0; 114398af571SMichael Ellerman } 115398af571SMichael Ellerman device_initcall(security_feature_debugfs_init); 116cb3d6759SMichal Suchanek #endif /* CONFIG_DEBUG_FS */ 117cb3d6759SMichal Suchanek 118d8f0e0b0SChristopher M. Riedl #if defined(CONFIG_PPC_FSL_BOOK3E) || defined(CONFIG_PPC_BOOK3S_64) 119f633a8adSDiana Craciun static int __init handle_nospectre_v2(char *p) 120f633a8adSDiana Craciun { 121f633a8adSDiana Craciun no_spectrev2 = true; 122f633a8adSDiana Craciun 123f633a8adSDiana Craciun return 0; 124f633a8adSDiana Craciun } 125f633a8adSDiana Craciun early_param("nospectre_v2", handle_nospectre_v2); 126d8f0e0b0SChristopher M. Riedl #endif /* CONFIG_PPC_FSL_BOOK3E || CONFIG_PPC_BOOK3S_64 */ 127d8f0e0b0SChristopher M. Riedl 128d8f0e0b0SChristopher M. Riedl #ifdef CONFIG_PPC_FSL_BOOK3E 129f633a8adSDiana Craciun void setup_spectre_v2(void) 130f633a8adSDiana Craciun { 131782e69efSJosh Poimboeuf if (no_spectrev2 || cpu_mitigations_off()) 132f633a8adSDiana Craciun do_btb_flush_fixups(); 133f633a8adSDiana Craciun else 134f633a8adSDiana Craciun btb_flush_enabled = true; 135f633a8adSDiana Craciun } 136f633a8adSDiana Craciun #endif /* CONFIG_PPC_FSL_BOOK3E */ 137f633a8adSDiana Craciun 138406d2b6aSDiana Craciun #ifdef CONFIG_PPC_BOOK3S_64 1398ad33041SMichael Ellerman ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, char *buf) 1408ad33041SMichael Ellerman { 141ff348355SMichael Ellerman bool thread_priv; 142ff348355SMichael Ellerman 143ff348355SMichael Ellerman thread_priv = security_ftr_enabled(SEC_FTR_L1D_THREAD_PRIV); 144ff348355SMichael Ellerman 145ff348355SMichael Ellerman if (rfi_flush || thread_priv) { 146ff348355SMichael Ellerman struct seq_buf s; 147ff348355SMichael Ellerman seq_buf_init(&s, buf, PAGE_SIZE - 1); 148ff348355SMichael Ellerman 149ff348355SMichael Ellerman seq_buf_printf(&s, "Mitigation: "); 150ff348355SMichael Ellerman 1518ad33041SMichael Ellerman if (rfi_flush) 152ff348355SMichael Ellerman seq_buf_printf(&s, "RFI Flush"); 153ff348355SMichael Ellerman 154ff348355SMichael Ellerman if (rfi_flush && thread_priv) 155ff348355SMichael Ellerman seq_buf_printf(&s, ", "); 156ff348355SMichael Ellerman 157ff348355SMichael Ellerman if (thread_priv) 158ff348355SMichael Ellerman seq_buf_printf(&s, "L1D private per thread"); 159ff348355SMichael Ellerman 160ff348355SMichael Ellerman seq_buf_printf(&s, "\n"); 161ff348355SMichael Ellerman 162ff348355SMichael Ellerman return s.len; 163ff348355SMichael Ellerman } 164ff348355SMichael Ellerman 165ff348355SMichael Ellerman if (!security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) && 166ff348355SMichael Ellerman !security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR)) 167ff348355SMichael Ellerman return sprintf(buf, "Not affected\n"); 1688ad33041SMichael Ellerman 1698ad33041SMichael Ellerman return sprintf(buf, "Vulnerable\n"); 1708ad33041SMichael Ellerman } 171406d2b6aSDiana Craciun #endif 17256986016SMichael Ellerman 17356986016SMichael Ellerman ssize_t cpu_show_spectre_v1(struct device *dev, struct device_attribute *attr, char *buf) 17456986016SMichael Ellerman { 1756d44acaeSMichael Ellerman struct seq_buf s; 17656986016SMichael Ellerman 1776d44acaeSMichael Ellerman seq_buf_init(&s, buf, PAGE_SIZE - 1); 1786d44acaeSMichael Ellerman 1796d44acaeSMichael Ellerman if (security_ftr_enabled(SEC_FTR_BNDS_CHK_SPEC_BAR)) { 180a3775145SMichal Suchanek if (barrier_nospec_enabled) 1816d44acaeSMichael Ellerman seq_buf_printf(&s, "Mitigation: __user pointer sanitization"); 1826d44acaeSMichael Ellerman else 1836d44acaeSMichael Ellerman seq_buf_printf(&s, "Vulnerable"); 184a3775145SMichal Suchanek 1856d44acaeSMichael Ellerman if (security_ftr_enabled(SEC_FTR_SPEC_BAR_ORI31)) 1866d44acaeSMichael Ellerman seq_buf_printf(&s, ", ori31 speculation barrier enabled"); 1876d44acaeSMichael Ellerman 1886d44acaeSMichael Ellerman seq_buf_printf(&s, "\n"); 1896d44acaeSMichael Ellerman } else 1906d44acaeSMichael Ellerman seq_buf_printf(&s, "Not affected\n"); 1916d44acaeSMichael Ellerman 1926d44acaeSMichael Ellerman return s.len; 19356986016SMichael Ellerman } 194d6fbe1c5SMichael Ellerman 195d6fbe1c5SMichael Ellerman ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr, char *buf) 196d6fbe1c5SMichael Ellerman { 197d6fbe1c5SMichael Ellerman struct seq_buf s; 1986d44acaeSMichael Ellerman bool bcs, ccd; 199d6fbe1c5SMichael Ellerman 200d6fbe1c5SMichael Ellerman seq_buf_init(&s, buf, PAGE_SIZE - 1); 201d6fbe1c5SMichael Ellerman 202d6fbe1c5SMichael Ellerman bcs = security_ftr_enabled(SEC_FTR_BCCTRL_SERIALISED); 203d6fbe1c5SMichael Ellerman ccd = security_ftr_enabled(SEC_FTR_COUNT_CACHE_DISABLED); 204d6fbe1c5SMichael Ellerman 20592edf8dfSMichael Ellerman if (bcs || ccd) { 206d6fbe1c5SMichael Ellerman seq_buf_printf(&s, "Mitigation: "); 207d6fbe1c5SMichael Ellerman 20892edf8dfSMichael Ellerman if (bcs) 209d6fbe1c5SMichael Ellerman seq_buf_printf(&s, "Indirect branch serialisation (kernel only)"); 210d6fbe1c5SMichael Ellerman 21192edf8dfSMichael Ellerman if (bcs && ccd) 212ee13cb24SMichael Ellerman seq_buf_printf(&s, ", "); 21392edf8dfSMichael Ellerman 21492edf8dfSMichael Ellerman if (ccd) 215ee13cb24SMichael Ellerman seq_buf_printf(&s, "Indirect branch cache disabled"); 21639e72bf9SMichael Ellerman 21739e72bf9SMichael Ellerman if (link_stack_flush_enabled) 21839e72bf9SMichael Ellerman seq_buf_printf(&s, ", Software link stack flush"); 21939e72bf9SMichael Ellerman 22092edf8dfSMichael Ellerman } else if (count_cache_flush_type != COUNT_CACHE_FLUSH_NONE) { 22192edf8dfSMichael Ellerman seq_buf_printf(&s, "Mitigation: Software count cache flush"); 222ee13cb24SMichael Ellerman 223ee13cb24SMichael Ellerman if (count_cache_flush_type == COUNT_CACHE_FLUSH_HW) 224ee13cb24SMichael Ellerman seq_buf_printf(&s, " (hardware accelerated)"); 22539e72bf9SMichael Ellerman 22639e72bf9SMichael Ellerman if (link_stack_flush_enabled) 22739e72bf9SMichael Ellerman seq_buf_printf(&s, ", Software link stack flush"); 22839e72bf9SMichael Ellerman 229dfa88658SDiana Craciun } else if (btb_flush_enabled) { 230dfa88658SDiana Craciun seq_buf_printf(&s, "Mitigation: Branch predictor state flush"); 231dfa88658SDiana Craciun } else { 232d6fbe1c5SMichael Ellerman seq_buf_printf(&s, "Vulnerable"); 233dfa88658SDiana Craciun } 234d6fbe1c5SMichael Ellerman 235d6fbe1c5SMichael Ellerman seq_buf_printf(&s, "\n"); 236d6fbe1c5SMichael Ellerman 237d6fbe1c5SMichael Ellerman return s.len; 238d6fbe1c5SMichael Ellerman } 239a048a07dSNicholas Piggin 2406453b532SDiana Craciun #ifdef CONFIG_PPC_BOOK3S_64 241a048a07dSNicholas Piggin /* 242a048a07dSNicholas Piggin * Store-forwarding barrier support. 243a048a07dSNicholas Piggin */ 244a048a07dSNicholas Piggin 245a048a07dSNicholas Piggin static enum stf_barrier_type stf_enabled_flush_types; 246a048a07dSNicholas Piggin static bool no_stf_barrier; 247a048a07dSNicholas Piggin bool stf_barrier; 248a048a07dSNicholas Piggin 249a048a07dSNicholas Piggin static int __init handle_no_stf_barrier(char *p) 250a048a07dSNicholas Piggin { 251a048a07dSNicholas Piggin pr_info("stf-barrier: disabled on command line."); 252a048a07dSNicholas Piggin no_stf_barrier = true; 253a048a07dSNicholas Piggin return 0; 254a048a07dSNicholas Piggin } 255a048a07dSNicholas Piggin 256a048a07dSNicholas Piggin early_param("no_stf_barrier", handle_no_stf_barrier); 257a048a07dSNicholas Piggin 258a048a07dSNicholas Piggin /* This is the generic flag used by other architectures */ 259a048a07dSNicholas Piggin static int __init handle_ssbd(char *p) 260a048a07dSNicholas Piggin { 261a048a07dSNicholas Piggin if (!p || strncmp(p, "auto", 5) == 0 || strncmp(p, "on", 2) == 0 ) { 262a048a07dSNicholas Piggin /* Until firmware tells us, we have the barrier with auto */ 263a048a07dSNicholas Piggin return 0; 264a048a07dSNicholas Piggin } else if (strncmp(p, "off", 3) == 0) { 265a048a07dSNicholas Piggin handle_no_stf_barrier(NULL); 266a048a07dSNicholas Piggin return 0; 267a048a07dSNicholas Piggin } else 268a048a07dSNicholas Piggin return 1; 269a048a07dSNicholas Piggin 270a048a07dSNicholas Piggin return 0; 271a048a07dSNicholas Piggin } 272a048a07dSNicholas Piggin early_param("spec_store_bypass_disable", handle_ssbd); 273a048a07dSNicholas Piggin 274a048a07dSNicholas Piggin /* This is the generic flag used by other architectures */ 275a048a07dSNicholas Piggin static int __init handle_no_ssbd(char *p) 276a048a07dSNicholas Piggin { 277a048a07dSNicholas Piggin handle_no_stf_barrier(NULL); 278a048a07dSNicholas Piggin return 0; 279a048a07dSNicholas Piggin } 280a048a07dSNicholas Piggin early_param("nospec_store_bypass_disable", handle_no_ssbd); 281a048a07dSNicholas Piggin 282a048a07dSNicholas Piggin static void stf_barrier_enable(bool enable) 283a048a07dSNicholas Piggin { 284a048a07dSNicholas Piggin if (enable) 285a048a07dSNicholas Piggin do_stf_barrier_fixups(stf_enabled_flush_types); 286a048a07dSNicholas Piggin else 287a048a07dSNicholas Piggin do_stf_barrier_fixups(STF_BARRIER_NONE); 288a048a07dSNicholas Piggin 289a048a07dSNicholas Piggin stf_barrier = enable; 290a048a07dSNicholas Piggin } 291a048a07dSNicholas Piggin 292a048a07dSNicholas Piggin void setup_stf_barrier(void) 293a048a07dSNicholas Piggin { 294a048a07dSNicholas Piggin enum stf_barrier_type type; 295a048a07dSNicholas Piggin bool enable, hv; 296a048a07dSNicholas Piggin 297a048a07dSNicholas Piggin hv = cpu_has_feature(CPU_FTR_HVMODE); 298a048a07dSNicholas Piggin 299a048a07dSNicholas Piggin /* Default to fallback in case fw-features are not available */ 300a048a07dSNicholas Piggin if (cpu_has_feature(CPU_FTR_ARCH_300)) 301a048a07dSNicholas Piggin type = STF_BARRIER_EIEIO; 302a048a07dSNicholas Piggin else if (cpu_has_feature(CPU_FTR_ARCH_207S)) 303a048a07dSNicholas Piggin type = STF_BARRIER_SYNC_ORI; 304a048a07dSNicholas Piggin else if (cpu_has_feature(CPU_FTR_ARCH_206)) 305a048a07dSNicholas Piggin type = STF_BARRIER_FALLBACK; 306a048a07dSNicholas Piggin else 307a048a07dSNicholas Piggin type = STF_BARRIER_NONE; 308a048a07dSNicholas Piggin 309a048a07dSNicholas Piggin enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) && 310a048a07dSNicholas Piggin (security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR) || 311a048a07dSNicholas Piggin (security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) && hv)); 312a048a07dSNicholas Piggin 313a048a07dSNicholas Piggin if (type == STF_BARRIER_FALLBACK) { 314a048a07dSNicholas Piggin pr_info("stf-barrier: fallback barrier available\n"); 315a048a07dSNicholas Piggin } else if (type == STF_BARRIER_SYNC_ORI) { 316a048a07dSNicholas Piggin pr_info("stf-barrier: hwsync barrier available\n"); 317a048a07dSNicholas Piggin } else if (type == STF_BARRIER_EIEIO) { 318a048a07dSNicholas Piggin pr_info("stf-barrier: eieio barrier available\n"); 319a048a07dSNicholas Piggin } 320a048a07dSNicholas Piggin 321a048a07dSNicholas Piggin stf_enabled_flush_types = type; 322a048a07dSNicholas Piggin 323782e69efSJosh Poimboeuf if (!no_stf_barrier && !cpu_mitigations_off()) 324a048a07dSNicholas Piggin stf_barrier_enable(enable); 325a048a07dSNicholas Piggin } 326a048a07dSNicholas Piggin 327a048a07dSNicholas Piggin ssize_t cpu_show_spec_store_bypass(struct device *dev, struct device_attribute *attr, char *buf) 328a048a07dSNicholas Piggin { 329a048a07dSNicholas Piggin if (stf_barrier && stf_enabled_flush_types != STF_BARRIER_NONE) { 330a048a07dSNicholas Piggin const char *type; 331a048a07dSNicholas Piggin switch (stf_enabled_flush_types) { 332a048a07dSNicholas Piggin case STF_BARRIER_EIEIO: 333a048a07dSNicholas Piggin type = "eieio"; 334a048a07dSNicholas Piggin break; 335a048a07dSNicholas Piggin case STF_BARRIER_SYNC_ORI: 336a048a07dSNicholas Piggin type = "hwsync"; 337a048a07dSNicholas Piggin break; 338a048a07dSNicholas Piggin case STF_BARRIER_FALLBACK: 339a048a07dSNicholas Piggin type = "fallback"; 340a048a07dSNicholas Piggin break; 341a048a07dSNicholas Piggin default: 342a048a07dSNicholas Piggin type = "unknown"; 343a048a07dSNicholas Piggin } 344a048a07dSNicholas Piggin return sprintf(buf, "Mitigation: Kernel entry/exit barrier (%s)\n", type); 345a048a07dSNicholas Piggin } 346a048a07dSNicholas Piggin 347a048a07dSNicholas Piggin if (!security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) && 348a048a07dSNicholas Piggin !security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR)) 349a048a07dSNicholas Piggin return sprintf(buf, "Not affected\n"); 350a048a07dSNicholas Piggin 351a048a07dSNicholas Piggin return sprintf(buf, "Vulnerable\n"); 352a048a07dSNicholas Piggin } 353a048a07dSNicholas Piggin 354a048a07dSNicholas Piggin #ifdef CONFIG_DEBUG_FS 355a048a07dSNicholas Piggin static int stf_barrier_set(void *data, u64 val) 356a048a07dSNicholas Piggin { 357a048a07dSNicholas Piggin bool enable; 358a048a07dSNicholas Piggin 359a048a07dSNicholas Piggin if (val == 1) 360a048a07dSNicholas Piggin enable = true; 361a048a07dSNicholas Piggin else if (val == 0) 362a048a07dSNicholas Piggin enable = false; 363a048a07dSNicholas Piggin else 364a048a07dSNicholas Piggin return -EINVAL; 365a048a07dSNicholas Piggin 366a048a07dSNicholas Piggin /* Only do anything if we're changing state */ 367a048a07dSNicholas Piggin if (enable != stf_barrier) 368a048a07dSNicholas Piggin stf_barrier_enable(enable); 369a048a07dSNicholas Piggin 370a048a07dSNicholas Piggin return 0; 371a048a07dSNicholas Piggin } 372a048a07dSNicholas Piggin 373a048a07dSNicholas Piggin static int stf_barrier_get(void *data, u64 *val) 374a048a07dSNicholas Piggin { 375a048a07dSNicholas Piggin *val = stf_barrier ? 1 : 0; 376a048a07dSNicholas Piggin return 0; 377a048a07dSNicholas Piggin } 378a048a07dSNicholas Piggin 379a048a07dSNicholas Piggin DEFINE_SIMPLE_ATTRIBUTE(fops_stf_barrier, stf_barrier_get, stf_barrier_set, "%llu\n"); 380a048a07dSNicholas Piggin 381a048a07dSNicholas Piggin static __init int stf_barrier_debugfs_init(void) 382a048a07dSNicholas Piggin { 383a048a07dSNicholas Piggin debugfs_create_file("stf_barrier", 0600, powerpc_debugfs_root, NULL, &fops_stf_barrier); 384a048a07dSNicholas Piggin return 0; 385a048a07dSNicholas Piggin } 386a048a07dSNicholas Piggin device_initcall(stf_barrier_debugfs_init); 387a048a07dSNicholas Piggin #endif /* CONFIG_DEBUG_FS */ 388ee13cb24SMichael Ellerman 38939e72bf9SMichael Ellerman static void no_count_cache_flush(void) 390ee13cb24SMichael Ellerman { 391ee13cb24SMichael Ellerman count_cache_flush_type = COUNT_CACHE_FLUSH_NONE; 392ee13cb24SMichael Ellerman pr_info("count-cache-flush: software flush disabled.\n"); 39339e72bf9SMichael Ellerman } 39439e72bf9SMichael Ellerman 39539e72bf9SMichael Ellerman static void toggle_count_cache_flush(bool enable) 39639e72bf9SMichael Ellerman { 39739e72bf9SMichael Ellerman if (!security_ftr_enabled(SEC_FTR_FLUSH_COUNT_CACHE) && 39839e72bf9SMichael Ellerman !security_ftr_enabled(SEC_FTR_FLUSH_LINK_STACK)) 39939e72bf9SMichael Ellerman enable = false; 40039e72bf9SMichael Ellerman 40139e72bf9SMichael Ellerman if (!enable) { 40239e72bf9SMichael Ellerman patch_instruction_site(&patch__call_flush_count_cache, PPC_INST_NOP); 403*af2e8c68SMichael Ellerman #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE 404*af2e8c68SMichael Ellerman patch_instruction_site(&patch__call_kvm_flush_link_stack, PPC_INST_NOP); 405*af2e8c68SMichael Ellerman #endif 40639e72bf9SMichael Ellerman pr_info("link-stack-flush: software flush disabled.\n"); 40739e72bf9SMichael Ellerman link_stack_flush_enabled = false; 40839e72bf9SMichael Ellerman no_count_cache_flush(); 409ee13cb24SMichael Ellerman return; 410ee13cb24SMichael Ellerman } 411ee13cb24SMichael Ellerman 41239e72bf9SMichael Ellerman // This enables the branch from _switch to flush_count_cache 413ee13cb24SMichael Ellerman patch_branch_site(&patch__call_flush_count_cache, 414ee13cb24SMichael Ellerman (u64)&flush_count_cache, BRANCH_SET_LINK); 415ee13cb24SMichael Ellerman 416*af2e8c68SMichael Ellerman #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE 417*af2e8c68SMichael Ellerman // This enables the branch from guest_exit_cont to kvm_flush_link_stack 418*af2e8c68SMichael Ellerman patch_branch_site(&patch__call_kvm_flush_link_stack, 419*af2e8c68SMichael Ellerman (u64)&kvm_flush_link_stack, BRANCH_SET_LINK); 420*af2e8c68SMichael Ellerman #endif 421*af2e8c68SMichael Ellerman 42239e72bf9SMichael Ellerman pr_info("link-stack-flush: software flush enabled.\n"); 42339e72bf9SMichael Ellerman link_stack_flush_enabled = true; 42439e72bf9SMichael Ellerman 42539e72bf9SMichael Ellerman // If we just need to flush the link stack, patch an early return 42639e72bf9SMichael Ellerman if (!security_ftr_enabled(SEC_FTR_FLUSH_COUNT_CACHE)) { 42739e72bf9SMichael Ellerman patch_instruction_site(&patch__flush_link_stack_return, PPC_INST_BLR); 42839e72bf9SMichael Ellerman no_count_cache_flush(); 42939e72bf9SMichael Ellerman return; 43039e72bf9SMichael Ellerman } 43139e72bf9SMichael Ellerman 432ee13cb24SMichael Ellerman if (!security_ftr_enabled(SEC_FTR_BCCTR_FLUSH_ASSIST)) { 433ee13cb24SMichael Ellerman count_cache_flush_type = COUNT_CACHE_FLUSH_SW; 434ee13cb24SMichael Ellerman pr_info("count-cache-flush: full software flush sequence enabled.\n"); 435ee13cb24SMichael Ellerman return; 436ee13cb24SMichael Ellerman } 437ee13cb24SMichael Ellerman 438ee13cb24SMichael Ellerman patch_instruction_site(&patch__flush_count_cache_return, PPC_INST_BLR); 439ee13cb24SMichael Ellerman count_cache_flush_type = COUNT_CACHE_FLUSH_HW; 440ee13cb24SMichael Ellerman pr_info("count-cache-flush: hardware assisted flush sequence enabled\n"); 441ee13cb24SMichael Ellerman } 442ee13cb24SMichael Ellerman 443ee13cb24SMichael Ellerman void setup_count_cache_flush(void) 444ee13cb24SMichael Ellerman { 445d8f0e0b0SChristopher M. Riedl bool enable = true; 446d8f0e0b0SChristopher M. Riedl 447d8f0e0b0SChristopher M. Riedl if (no_spectrev2 || cpu_mitigations_off()) { 448d8f0e0b0SChristopher M. Riedl if (security_ftr_enabled(SEC_FTR_BCCTRL_SERIALISED) || 449d8f0e0b0SChristopher M. Riedl security_ftr_enabled(SEC_FTR_COUNT_CACHE_DISABLED)) 45039e72bf9SMichael Ellerman pr_warn("Spectre v2 mitigations not fully under software control, can't disable\n"); 451d8f0e0b0SChristopher M. Riedl 452d8f0e0b0SChristopher M. Riedl enable = false; 453d8f0e0b0SChristopher M. Riedl } 454d8f0e0b0SChristopher M. Riedl 45539e72bf9SMichael Ellerman /* 45639e72bf9SMichael Ellerman * There's no firmware feature flag/hypervisor bit to tell us we need to 45739e72bf9SMichael Ellerman * flush the link stack on context switch. So we set it here if we see 45839e72bf9SMichael Ellerman * either of the Spectre v2 mitigations that aim to protect userspace. 45939e72bf9SMichael Ellerman */ 46039e72bf9SMichael Ellerman if (security_ftr_enabled(SEC_FTR_COUNT_CACHE_DISABLED) || 46139e72bf9SMichael Ellerman security_ftr_enabled(SEC_FTR_FLUSH_COUNT_CACHE)) 46239e72bf9SMichael Ellerman security_ftr_set(SEC_FTR_FLUSH_LINK_STACK); 46339e72bf9SMichael Ellerman 464d8f0e0b0SChristopher M. Riedl toggle_count_cache_flush(enable); 465ee13cb24SMichael Ellerman } 466ee13cb24SMichael Ellerman 467ee13cb24SMichael Ellerman #ifdef CONFIG_DEBUG_FS 468ee13cb24SMichael Ellerman static int count_cache_flush_set(void *data, u64 val) 469ee13cb24SMichael Ellerman { 470ee13cb24SMichael Ellerman bool enable; 471ee13cb24SMichael Ellerman 472ee13cb24SMichael Ellerman if (val == 1) 473ee13cb24SMichael Ellerman enable = true; 474ee13cb24SMichael Ellerman else if (val == 0) 475ee13cb24SMichael Ellerman enable = false; 476ee13cb24SMichael Ellerman else 477ee13cb24SMichael Ellerman return -EINVAL; 478ee13cb24SMichael Ellerman 479ee13cb24SMichael Ellerman toggle_count_cache_flush(enable); 480ee13cb24SMichael Ellerman 481ee13cb24SMichael Ellerman return 0; 482ee13cb24SMichael Ellerman } 483ee13cb24SMichael Ellerman 484ee13cb24SMichael Ellerman static int count_cache_flush_get(void *data, u64 *val) 485ee13cb24SMichael Ellerman { 486ee13cb24SMichael Ellerman if (count_cache_flush_type == COUNT_CACHE_FLUSH_NONE) 487ee13cb24SMichael Ellerman *val = 0; 488ee13cb24SMichael Ellerman else 489ee13cb24SMichael Ellerman *val = 1; 490ee13cb24SMichael Ellerman 491ee13cb24SMichael Ellerman return 0; 492ee13cb24SMichael Ellerman } 493ee13cb24SMichael Ellerman 494ee13cb24SMichael Ellerman DEFINE_SIMPLE_ATTRIBUTE(fops_count_cache_flush, count_cache_flush_get, 495ee13cb24SMichael Ellerman count_cache_flush_set, "%llu\n"); 496ee13cb24SMichael Ellerman 497ee13cb24SMichael Ellerman static __init int count_cache_flush_debugfs_init(void) 498ee13cb24SMichael Ellerman { 499ee13cb24SMichael Ellerman debugfs_create_file("count_cache_flush", 0600, powerpc_debugfs_root, 500ee13cb24SMichael Ellerman NULL, &fops_count_cache_flush); 501ee13cb24SMichael Ellerman return 0; 502ee13cb24SMichael Ellerman } 503ee13cb24SMichael Ellerman device_initcall(count_cache_flush_debugfs_init); 504ee13cb24SMichael Ellerman #endif /* CONFIG_DEBUG_FS */ 5056453b532SDiana Craciun #endif /* CONFIG_PPC_BOOK3S_64 */ 506