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 193b05a1e5SGeert Uytterhoeven u64 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; 27ee13cb24SMichael Ellerman 28815069caSMichal Suchanek bool barrier_nospec_enabled; 29cf175dc3SDiana Craciun static bool no_nospec; 30f633a8adSDiana Craciun static bool btb_flush_enabled; 31d8f0e0b0SChristopher M. Riedl #if defined(CONFIG_PPC_FSL_BOOK3E) || defined(CONFIG_PPC_BOOK3S_64) 32f633a8adSDiana Craciun static bool no_spectrev2; 33f633a8adSDiana Craciun #endif 342eea7f06SMichal Suchanek 352eea7f06SMichal Suchanek static void enable_barrier_nospec(bool enable) 362eea7f06SMichal Suchanek { 372eea7f06SMichal Suchanek barrier_nospec_enabled = enable; 382eea7f06SMichal Suchanek do_barrier_nospec_fixups(enable); 392eea7f06SMichal Suchanek } 402eea7f06SMichal Suchanek 41cb3d6759SMichal Suchanek void setup_barrier_nospec(void) 42cb3d6759SMichal Suchanek { 43cb3d6759SMichal Suchanek bool enable; 44cb3d6759SMichal Suchanek 45cb3d6759SMichal Suchanek /* 46cb3d6759SMichal Suchanek * It would make sense to check SEC_FTR_SPEC_BAR_ORI31 below as well. 47cb3d6759SMichal Suchanek * But there's a good reason not to. The two flags we check below are 48cb3d6759SMichal Suchanek * both are enabled by default in the kernel, so if the hcall is not 49cb3d6759SMichal Suchanek * functional they will be enabled. 50cb3d6759SMichal Suchanek * On a system where the host firmware has been updated (so the ori 51cb3d6759SMichal Suchanek * functions as a barrier), but on which the hypervisor (KVM/Qemu) has 52cb3d6759SMichal Suchanek * not been updated, we would like to enable the barrier. Dropping the 53cb3d6759SMichal Suchanek * check for SEC_FTR_SPEC_BAR_ORI31 achieves that. The only downside is 54cb3d6759SMichal Suchanek * we potentially enable the barrier on systems where the host firmware 55cb3d6759SMichal Suchanek * is not updated, but that's harmless as it's a no-op. 56cb3d6759SMichal Suchanek */ 57cb3d6759SMichal Suchanek enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) && 58cb3d6759SMichal Suchanek security_ftr_enabled(SEC_FTR_BNDS_CHK_SPEC_BAR); 59cb3d6759SMichal Suchanek 60782e69efSJosh Poimboeuf if (!no_nospec && !cpu_mitigations_off()) 61cb3d6759SMichal Suchanek enable_barrier_nospec(enable); 62cb3d6759SMichal Suchanek } 63cb3d6759SMichal Suchanek 64cf175dc3SDiana Craciun static int __init handle_nospectre_v1(char *p) 65cf175dc3SDiana Craciun { 66cf175dc3SDiana Craciun no_nospec = true; 67cf175dc3SDiana Craciun 68cf175dc3SDiana Craciun return 0; 69cf175dc3SDiana Craciun } 70cf175dc3SDiana Craciun early_param("nospectre_v1", handle_nospectre_v1); 71cf175dc3SDiana Craciun 72cb3d6759SMichal Suchanek #ifdef CONFIG_DEBUG_FS 73cb3d6759SMichal Suchanek static int barrier_nospec_set(void *data, u64 val) 74cb3d6759SMichal Suchanek { 75cb3d6759SMichal Suchanek switch (val) { 76cb3d6759SMichal Suchanek case 0: 77cb3d6759SMichal Suchanek case 1: 78cb3d6759SMichal Suchanek break; 79cb3d6759SMichal Suchanek default: 80cb3d6759SMichal Suchanek return -EINVAL; 81cb3d6759SMichal Suchanek } 82cb3d6759SMichal Suchanek 83cb3d6759SMichal Suchanek if (!!val == !!barrier_nospec_enabled) 84cb3d6759SMichal Suchanek return 0; 85cb3d6759SMichal Suchanek 86cb3d6759SMichal Suchanek enable_barrier_nospec(!!val); 87cb3d6759SMichal Suchanek 88cb3d6759SMichal Suchanek return 0; 89cb3d6759SMichal Suchanek } 90cb3d6759SMichal Suchanek 91cb3d6759SMichal Suchanek static int barrier_nospec_get(void *data, u64 *val) 92cb3d6759SMichal Suchanek { 93cb3d6759SMichal Suchanek *val = barrier_nospec_enabled ? 1 : 0; 94cb3d6759SMichal Suchanek return 0; 95cb3d6759SMichal Suchanek } 96cb3d6759SMichal Suchanek 97cb3d6759SMichal Suchanek DEFINE_SIMPLE_ATTRIBUTE(fops_barrier_nospec, 98cb3d6759SMichal Suchanek barrier_nospec_get, barrier_nospec_set, "%llu\n"); 99cb3d6759SMichal Suchanek 100cb3d6759SMichal Suchanek static __init int barrier_nospec_debugfs_init(void) 101cb3d6759SMichal Suchanek { 102cb3d6759SMichal Suchanek debugfs_create_file("barrier_nospec", 0600, powerpc_debugfs_root, NULL, 103cb3d6759SMichal Suchanek &fops_barrier_nospec); 104cb3d6759SMichal Suchanek return 0; 105cb3d6759SMichal Suchanek } 106cb3d6759SMichal Suchanek device_initcall(barrier_nospec_debugfs_init); 107398af571SMichael Ellerman 108398af571SMichael Ellerman static __init int security_feature_debugfs_init(void) 109398af571SMichael Ellerman { 110398af571SMichael Ellerman debugfs_create_x64("security_features", 0400, powerpc_debugfs_root, 1113b05a1e5SGeert Uytterhoeven &powerpc_security_features); 112398af571SMichael Ellerman return 0; 113398af571SMichael Ellerman } 114398af571SMichael Ellerman device_initcall(security_feature_debugfs_init); 115cb3d6759SMichal Suchanek #endif /* CONFIG_DEBUG_FS */ 116cb3d6759SMichal Suchanek 117d8f0e0b0SChristopher M. Riedl #if defined(CONFIG_PPC_FSL_BOOK3E) || defined(CONFIG_PPC_BOOK3S_64) 118f633a8adSDiana Craciun static int __init handle_nospectre_v2(char *p) 119f633a8adSDiana Craciun { 120f633a8adSDiana Craciun no_spectrev2 = true; 121f633a8adSDiana Craciun 122f633a8adSDiana Craciun return 0; 123f633a8adSDiana Craciun } 124f633a8adSDiana Craciun early_param("nospectre_v2", handle_nospectre_v2); 125d8f0e0b0SChristopher M. Riedl #endif /* CONFIG_PPC_FSL_BOOK3E || CONFIG_PPC_BOOK3S_64 */ 126d8f0e0b0SChristopher M. Riedl 127d8f0e0b0SChristopher M. Riedl #ifdef CONFIG_PPC_FSL_BOOK3E 128f633a8adSDiana Craciun void setup_spectre_v2(void) 129f633a8adSDiana Craciun { 130782e69efSJosh Poimboeuf if (no_spectrev2 || cpu_mitigations_off()) 131f633a8adSDiana Craciun do_btb_flush_fixups(); 132f633a8adSDiana Craciun else 133f633a8adSDiana Craciun btb_flush_enabled = true; 134f633a8adSDiana Craciun } 135f633a8adSDiana Craciun #endif /* CONFIG_PPC_FSL_BOOK3E */ 136f633a8adSDiana Craciun 137406d2b6aSDiana Craciun #ifdef CONFIG_PPC_BOOK3S_64 1388ad33041SMichael Ellerman ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, char *buf) 1398ad33041SMichael Ellerman { 140ff348355SMichael Ellerman bool thread_priv; 141ff348355SMichael Ellerman 142ff348355SMichael Ellerman thread_priv = security_ftr_enabled(SEC_FTR_L1D_THREAD_PRIV); 143ff348355SMichael Ellerman 144*4e706af3SGustavo L. F. Walbon if (rfi_flush) { 145ff348355SMichael Ellerman struct seq_buf s; 146ff348355SMichael Ellerman seq_buf_init(&s, buf, PAGE_SIZE - 1); 147ff348355SMichael Ellerman 148*4e706af3SGustavo L. F. Walbon seq_buf_printf(&s, "Mitigation: RFI Flush"); 149ff348355SMichael Ellerman if (thread_priv) 150*4e706af3SGustavo L. F. Walbon seq_buf_printf(&s, ", L1D private per thread"); 151ff348355SMichael Ellerman 152ff348355SMichael Ellerman seq_buf_printf(&s, "\n"); 153ff348355SMichael Ellerman 154ff348355SMichael Ellerman return s.len; 155ff348355SMichael Ellerman } 156ff348355SMichael Ellerman 157*4e706af3SGustavo L. F. Walbon if (thread_priv) 158*4e706af3SGustavo L. F. Walbon return sprintf(buf, "Vulnerable: L1D private per thread\n"); 159*4e706af3SGustavo L. F. Walbon 160ff348355SMichael Ellerman if (!security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) && 161ff348355SMichael Ellerman !security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR)) 162ff348355SMichael Ellerman return sprintf(buf, "Not affected\n"); 1638ad33041SMichael Ellerman 1648ad33041SMichael Ellerman return sprintf(buf, "Vulnerable\n"); 1658ad33041SMichael Ellerman } 1668e6b6da9SAnthony Steinhauser 1678e6b6da9SAnthony Steinhauser ssize_t cpu_show_l1tf(struct device *dev, struct device_attribute *attr, char *buf) 1688e6b6da9SAnthony Steinhauser { 1698e6b6da9SAnthony Steinhauser return cpu_show_meltdown(dev, attr, buf); 1708e6b6da9SAnthony Steinhauser } 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"); 21692edf8dfSMichael Ellerman } else if (count_cache_flush_type != COUNT_CACHE_FLUSH_NONE) { 21792edf8dfSMichael Ellerman seq_buf_printf(&s, "Mitigation: Software count cache flush"); 218ee13cb24SMichael Ellerman 219ee13cb24SMichael Ellerman if (count_cache_flush_type == COUNT_CACHE_FLUSH_HW) 220ee13cb24SMichael Ellerman seq_buf_printf(&s, " (hardware accelerated)"); 221dfa88658SDiana Craciun } else if (btb_flush_enabled) { 222dfa88658SDiana Craciun seq_buf_printf(&s, "Mitigation: Branch predictor state flush"); 223dfa88658SDiana Craciun } else { 224d6fbe1c5SMichael Ellerman seq_buf_printf(&s, "Vulnerable"); 225dfa88658SDiana Craciun } 226d6fbe1c5SMichael Ellerman 227d6fbe1c5SMichael Ellerman seq_buf_printf(&s, "\n"); 228d6fbe1c5SMichael Ellerman 229d6fbe1c5SMichael Ellerman return s.len; 230d6fbe1c5SMichael Ellerman } 231a048a07dSNicholas Piggin 2326453b532SDiana Craciun #ifdef CONFIG_PPC_BOOK3S_64 233a048a07dSNicholas Piggin /* 234a048a07dSNicholas Piggin * Store-forwarding barrier support. 235a048a07dSNicholas Piggin */ 236a048a07dSNicholas Piggin 237a048a07dSNicholas Piggin static enum stf_barrier_type stf_enabled_flush_types; 238a048a07dSNicholas Piggin static bool no_stf_barrier; 239a048a07dSNicholas Piggin bool stf_barrier; 240a048a07dSNicholas Piggin 241a048a07dSNicholas Piggin static int __init handle_no_stf_barrier(char *p) 242a048a07dSNicholas Piggin { 243a048a07dSNicholas Piggin pr_info("stf-barrier: disabled on command line."); 244a048a07dSNicholas Piggin no_stf_barrier = true; 245a048a07dSNicholas Piggin return 0; 246a048a07dSNicholas Piggin } 247a048a07dSNicholas Piggin 248a048a07dSNicholas Piggin early_param("no_stf_barrier", handle_no_stf_barrier); 249a048a07dSNicholas Piggin 250a048a07dSNicholas Piggin /* This is the generic flag used by other architectures */ 251a048a07dSNicholas Piggin static int __init handle_ssbd(char *p) 252a048a07dSNicholas Piggin { 253a048a07dSNicholas Piggin if (!p || strncmp(p, "auto", 5) == 0 || strncmp(p, "on", 2) == 0 ) { 254a048a07dSNicholas Piggin /* Until firmware tells us, we have the barrier with auto */ 255a048a07dSNicholas Piggin return 0; 256a048a07dSNicholas Piggin } else if (strncmp(p, "off", 3) == 0) { 257a048a07dSNicholas Piggin handle_no_stf_barrier(NULL); 258a048a07dSNicholas Piggin return 0; 259a048a07dSNicholas Piggin } else 260a048a07dSNicholas Piggin return 1; 261a048a07dSNicholas Piggin 262a048a07dSNicholas Piggin return 0; 263a048a07dSNicholas Piggin } 264a048a07dSNicholas Piggin early_param("spec_store_bypass_disable", handle_ssbd); 265a048a07dSNicholas Piggin 266a048a07dSNicholas Piggin /* This is the generic flag used by other architectures */ 267a048a07dSNicholas Piggin static int __init handle_no_ssbd(char *p) 268a048a07dSNicholas Piggin { 269a048a07dSNicholas Piggin handle_no_stf_barrier(NULL); 270a048a07dSNicholas Piggin return 0; 271a048a07dSNicholas Piggin } 272a048a07dSNicholas Piggin early_param("nospec_store_bypass_disable", handle_no_ssbd); 273a048a07dSNicholas Piggin 274a048a07dSNicholas Piggin static void stf_barrier_enable(bool enable) 275a048a07dSNicholas Piggin { 276a048a07dSNicholas Piggin if (enable) 277a048a07dSNicholas Piggin do_stf_barrier_fixups(stf_enabled_flush_types); 278a048a07dSNicholas Piggin else 279a048a07dSNicholas Piggin do_stf_barrier_fixups(STF_BARRIER_NONE); 280a048a07dSNicholas Piggin 281a048a07dSNicholas Piggin stf_barrier = enable; 282a048a07dSNicholas Piggin } 283a048a07dSNicholas Piggin 284a048a07dSNicholas Piggin void setup_stf_barrier(void) 285a048a07dSNicholas Piggin { 286a048a07dSNicholas Piggin enum stf_barrier_type type; 287a048a07dSNicholas Piggin bool enable, hv; 288a048a07dSNicholas Piggin 289a048a07dSNicholas Piggin hv = cpu_has_feature(CPU_FTR_HVMODE); 290a048a07dSNicholas Piggin 291a048a07dSNicholas Piggin /* Default to fallback in case fw-features are not available */ 292a048a07dSNicholas Piggin if (cpu_has_feature(CPU_FTR_ARCH_300)) 293a048a07dSNicholas Piggin type = STF_BARRIER_EIEIO; 294a048a07dSNicholas Piggin else if (cpu_has_feature(CPU_FTR_ARCH_207S)) 295a048a07dSNicholas Piggin type = STF_BARRIER_SYNC_ORI; 296a048a07dSNicholas Piggin else if (cpu_has_feature(CPU_FTR_ARCH_206)) 297a048a07dSNicholas Piggin type = STF_BARRIER_FALLBACK; 298a048a07dSNicholas Piggin else 299a048a07dSNicholas Piggin type = STF_BARRIER_NONE; 300a048a07dSNicholas Piggin 301a048a07dSNicholas Piggin enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) && 302a048a07dSNicholas Piggin (security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR) || 303a048a07dSNicholas Piggin (security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) && hv)); 304a048a07dSNicholas Piggin 305a048a07dSNicholas Piggin if (type == STF_BARRIER_FALLBACK) { 306a048a07dSNicholas Piggin pr_info("stf-barrier: fallback barrier available\n"); 307a048a07dSNicholas Piggin } else if (type == STF_BARRIER_SYNC_ORI) { 308a048a07dSNicholas Piggin pr_info("stf-barrier: hwsync barrier available\n"); 309a048a07dSNicholas Piggin } else if (type == STF_BARRIER_EIEIO) { 310a048a07dSNicholas Piggin pr_info("stf-barrier: eieio barrier available\n"); 311a048a07dSNicholas Piggin } 312a048a07dSNicholas Piggin 313a048a07dSNicholas Piggin stf_enabled_flush_types = type; 314a048a07dSNicholas Piggin 315782e69efSJosh Poimboeuf if (!no_stf_barrier && !cpu_mitigations_off()) 316a048a07dSNicholas Piggin stf_barrier_enable(enable); 317a048a07dSNicholas Piggin } 318a048a07dSNicholas Piggin 319a048a07dSNicholas Piggin ssize_t cpu_show_spec_store_bypass(struct device *dev, struct device_attribute *attr, char *buf) 320a048a07dSNicholas Piggin { 321a048a07dSNicholas Piggin if (stf_barrier && stf_enabled_flush_types != STF_BARRIER_NONE) { 322a048a07dSNicholas Piggin const char *type; 323a048a07dSNicholas Piggin switch (stf_enabled_flush_types) { 324a048a07dSNicholas Piggin case STF_BARRIER_EIEIO: 325a048a07dSNicholas Piggin type = "eieio"; 326a048a07dSNicholas Piggin break; 327a048a07dSNicholas Piggin case STF_BARRIER_SYNC_ORI: 328a048a07dSNicholas Piggin type = "hwsync"; 329a048a07dSNicholas Piggin break; 330a048a07dSNicholas Piggin case STF_BARRIER_FALLBACK: 331a048a07dSNicholas Piggin type = "fallback"; 332a048a07dSNicholas Piggin break; 333a048a07dSNicholas Piggin default: 334a048a07dSNicholas Piggin type = "unknown"; 335a048a07dSNicholas Piggin } 336a048a07dSNicholas Piggin return sprintf(buf, "Mitigation: Kernel entry/exit barrier (%s)\n", type); 337a048a07dSNicholas Piggin } 338a048a07dSNicholas Piggin 339a048a07dSNicholas Piggin if (!security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) && 340a048a07dSNicholas Piggin !security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR)) 341a048a07dSNicholas Piggin return sprintf(buf, "Not affected\n"); 342a048a07dSNicholas Piggin 343a048a07dSNicholas Piggin return sprintf(buf, "Vulnerable\n"); 344a048a07dSNicholas Piggin } 345a048a07dSNicholas Piggin 346a048a07dSNicholas Piggin #ifdef CONFIG_DEBUG_FS 347a048a07dSNicholas Piggin static int stf_barrier_set(void *data, u64 val) 348a048a07dSNicholas Piggin { 349a048a07dSNicholas Piggin bool enable; 350a048a07dSNicholas Piggin 351a048a07dSNicholas Piggin if (val == 1) 352a048a07dSNicholas Piggin enable = true; 353a048a07dSNicholas Piggin else if (val == 0) 354a048a07dSNicholas Piggin enable = false; 355a048a07dSNicholas Piggin else 356a048a07dSNicholas Piggin return -EINVAL; 357a048a07dSNicholas Piggin 358a048a07dSNicholas Piggin /* Only do anything if we're changing state */ 359a048a07dSNicholas Piggin if (enable != stf_barrier) 360a048a07dSNicholas Piggin stf_barrier_enable(enable); 361a048a07dSNicholas Piggin 362a048a07dSNicholas Piggin return 0; 363a048a07dSNicholas Piggin } 364a048a07dSNicholas Piggin 365a048a07dSNicholas Piggin static int stf_barrier_get(void *data, u64 *val) 366a048a07dSNicholas Piggin { 367a048a07dSNicholas Piggin *val = stf_barrier ? 1 : 0; 368a048a07dSNicholas Piggin return 0; 369a048a07dSNicholas Piggin } 370a048a07dSNicholas Piggin 371a048a07dSNicholas Piggin DEFINE_SIMPLE_ATTRIBUTE(fops_stf_barrier, stf_barrier_get, stf_barrier_set, "%llu\n"); 372a048a07dSNicholas Piggin 373a048a07dSNicholas Piggin static __init int stf_barrier_debugfs_init(void) 374a048a07dSNicholas Piggin { 375a048a07dSNicholas Piggin debugfs_create_file("stf_barrier", 0600, powerpc_debugfs_root, NULL, &fops_stf_barrier); 376a048a07dSNicholas Piggin return 0; 377a048a07dSNicholas Piggin } 378a048a07dSNicholas Piggin device_initcall(stf_barrier_debugfs_init); 379a048a07dSNicholas Piggin #endif /* CONFIG_DEBUG_FS */ 380ee13cb24SMichael Ellerman 381ee13cb24SMichael Ellerman static void toggle_count_cache_flush(bool enable) 382ee13cb24SMichael Ellerman { 383ee13cb24SMichael Ellerman if (!enable || !security_ftr_enabled(SEC_FTR_FLUSH_COUNT_CACHE)) { 384ee13cb24SMichael Ellerman patch_instruction_site(&patch__call_flush_count_cache, PPC_INST_NOP); 385ee13cb24SMichael Ellerman count_cache_flush_type = COUNT_CACHE_FLUSH_NONE; 386ee13cb24SMichael Ellerman pr_info("count-cache-flush: software flush disabled.\n"); 387ee13cb24SMichael Ellerman return; 388ee13cb24SMichael Ellerman } 389ee13cb24SMichael Ellerman 390ee13cb24SMichael Ellerman patch_branch_site(&patch__call_flush_count_cache, 391ee13cb24SMichael Ellerman (u64)&flush_count_cache, BRANCH_SET_LINK); 392ee13cb24SMichael Ellerman 393ee13cb24SMichael Ellerman if (!security_ftr_enabled(SEC_FTR_BCCTR_FLUSH_ASSIST)) { 394ee13cb24SMichael Ellerman count_cache_flush_type = COUNT_CACHE_FLUSH_SW; 395ee13cb24SMichael Ellerman pr_info("count-cache-flush: full software flush sequence enabled.\n"); 396ee13cb24SMichael Ellerman return; 397ee13cb24SMichael Ellerman } 398ee13cb24SMichael Ellerman 399ee13cb24SMichael Ellerman patch_instruction_site(&patch__flush_count_cache_return, PPC_INST_BLR); 400ee13cb24SMichael Ellerman count_cache_flush_type = COUNT_CACHE_FLUSH_HW; 401ee13cb24SMichael Ellerman pr_info("count-cache-flush: hardware assisted flush sequence enabled\n"); 402ee13cb24SMichael Ellerman } 403ee13cb24SMichael Ellerman 404ee13cb24SMichael Ellerman void setup_count_cache_flush(void) 405ee13cb24SMichael Ellerman { 406d8f0e0b0SChristopher M. Riedl bool enable = true; 407d8f0e0b0SChristopher M. Riedl 408d8f0e0b0SChristopher M. Riedl if (no_spectrev2 || cpu_mitigations_off()) { 409d8f0e0b0SChristopher M. Riedl if (security_ftr_enabled(SEC_FTR_BCCTRL_SERIALISED) || 410d8f0e0b0SChristopher M. Riedl security_ftr_enabled(SEC_FTR_COUNT_CACHE_DISABLED)) 411d8f0e0b0SChristopher M. Riedl pr_warn("Spectre v2 mitigations not under software control, can't disable\n"); 412d8f0e0b0SChristopher M. Riedl 413d8f0e0b0SChristopher M. Riedl enable = false; 414d8f0e0b0SChristopher M. Riedl } 415d8f0e0b0SChristopher M. Riedl 416d8f0e0b0SChristopher M. Riedl toggle_count_cache_flush(enable); 417ee13cb24SMichael Ellerman } 418ee13cb24SMichael Ellerman 419ee13cb24SMichael Ellerman #ifdef CONFIG_DEBUG_FS 420ee13cb24SMichael Ellerman static int count_cache_flush_set(void *data, u64 val) 421ee13cb24SMichael Ellerman { 422ee13cb24SMichael Ellerman bool enable; 423ee13cb24SMichael Ellerman 424ee13cb24SMichael Ellerman if (val == 1) 425ee13cb24SMichael Ellerman enable = true; 426ee13cb24SMichael Ellerman else if (val == 0) 427ee13cb24SMichael Ellerman enable = false; 428ee13cb24SMichael Ellerman else 429ee13cb24SMichael Ellerman return -EINVAL; 430ee13cb24SMichael Ellerman 431ee13cb24SMichael Ellerman toggle_count_cache_flush(enable); 432ee13cb24SMichael Ellerman 433ee13cb24SMichael Ellerman return 0; 434ee13cb24SMichael Ellerman } 435ee13cb24SMichael Ellerman 436ee13cb24SMichael Ellerman static int count_cache_flush_get(void *data, u64 *val) 437ee13cb24SMichael Ellerman { 438ee13cb24SMichael Ellerman if (count_cache_flush_type == COUNT_CACHE_FLUSH_NONE) 439ee13cb24SMichael Ellerman *val = 0; 440ee13cb24SMichael Ellerman else 441ee13cb24SMichael Ellerman *val = 1; 442ee13cb24SMichael Ellerman 443ee13cb24SMichael Ellerman return 0; 444ee13cb24SMichael Ellerman } 445ee13cb24SMichael Ellerman 446ee13cb24SMichael Ellerman DEFINE_SIMPLE_ATTRIBUTE(fops_count_cache_flush, count_cache_flush_get, 447ee13cb24SMichael Ellerman count_cache_flush_set, "%llu\n"); 448ee13cb24SMichael Ellerman 449ee13cb24SMichael Ellerman static __init int count_cache_flush_debugfs_init(void) 450ee13cb24SMichael Ellerman { 451ee13cb24SMichael Ellerman debugfs_create_file("count_cache_flush", 0600, powerpc_debugfs_root, 452ee13cb24SMichael Ellerman NULL, &fops_count_cache_flush); 453ee13cb24SMichael Ellerman return 0; 454ee13cb24SMichael Ellerman } 455ee13cb24SMichael Ellerman device_initcall(count_cache_flush_debugfs_init); 456ee13cb24SMichael Ellerman #endif /* CONFIG_DEBUG_FS */ 4576453b532SDiana Craciun #endif /* CONFIG_PPC_BOOK3S_64 */ 458