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> 10d93e5e2dSMichael Ellerman #include <linux/nospec.h> 11d93e5e2dSMichael Ellerman #include <linux/prctl.h> 12ff348355SMichael Ellerman #include <linux/seq_buf.h> 138ad33041SMichael Ellerman 14ee13cb24SMichael Ellerman #include <asm/asm-prototypes.h> 15ee13cb24SMichael Ellerman #include <asm/code-patching.h> 16a048a07dSNicholas Piggin #include <asm/debugfs.h> 179a868f63SMichael Ellerman #include <asm/security_features.h> 182eea7f06SMichal Suchanek #include <asm/setup.h> 1975346251SJordan Niethe #include <asm/inst.h> 209a868f63SMichael Ellerman 219a868f63SMichael Ellerman 223b05a1e5SGeert Uytterhoeven u64 powerpc_security_features __read_mostly = SEC_FTR_DEFAULT; 238ad33041SMichael Ellerman 241026798cSNicholas Piggin enum branch_cache_flush_type { 251026798cSNicholas Piggin BRANCH_CACHE_FLUSH_NONE = 0x1, 261026798cSNicholas Piggin BRANCH_CACHE_FLUSH_SW = 0x2, 271026798cSNicholas Piggin BRANCH_CACHE_FLUSH_HW = 0x4, 28ee13cb24SMichael Ellerman }; 291026798cSNicholas Piggin static enum branch_cache_flush_type count_cache_flush_type = BRANCH_CACHE_FLUSH_NONE; 30c06ac277SNicholas Piggin static enum branch_cache_flush_type link_stack_flush_type = BRANCH_CACHE_FLUSH_NONE; 31ee13cb24SMichael Ellerman 32815069caSMichal Suchanek bool barrier_nospec_enabled; 33cf175dc3SDiana Craciun static bool no_nospec; 34f633a8adSDiana Craciun static bool btb_flush_enabled; 35d8f0e0b0SChristopher M. Riedl #if defined(CONFIG_PPC_FSL_BOOK3E) || defined(CONFIG_PPC_BOOK3S_64) 36f633a8adSDiana Craciun static bool no_spectrev2; 37f633a8adSDiana Craciun #endif 382eea7f06SMichal Suchanek 392eea7f06SMichal Suchanek static void enable_barrier_nospec(bool enable) 402eea7f06SMichal Suchanek { 412eea7f06SMichal Suchanek barrier_nospec_enabled = enable; 422eea7f06SMichal Suchanek do_barrier_nospec_fixups(enable); 432eea7f06SMichal Suchanek } 442eea7f06SMichal Suchanek 45cb3d6759SMichal Suchanek void setup_barrier_nospec(void) 46cb3d6759SMichal Suchanek { 47cb3d6759SMichal Suchanek bool enable; 48cb3d6759SMichal Suchanek 49cb3d6759SMichal Suchanek /* 50cb3d6759SMichal Suchanek * It would make sense to check SEC_FTR_SPEC_BAR_ORI31 below as well. 51cb3d6759SMichal Suchanek * But there's a good reason not to. The two flags we check below are 52cb3d6759SMichal Suchanek * both are enabled by default in the kernel, so if the hcall is not 53cb3d6759SMichal Suchanek * functional they will be enabled. 54cb3d6759SMichal Suchanek * On a system where the host firmware has been updated (so the ori 55cb3d6759SMichal Suchanek * functions as a barrier), but on which the hypervisor (KVM/Qemu) has 56cb3d6759SMichal Suchanek * not been updated, we would like to enable the barrier. Dropping the 57cb3d6759SMichal Suchanek * check for SEC_FTR_SPEC_BAR_ORI31 achieves that. The only downside is 58cb3d6759SMichal Suchanek * we potentially enable the barrier on systems where the host firmware 59cb3d6759SMichal Suchanek * is not updated, but that's harmless as it's a no-op. 60cb3d6759SMichal Suchanek */ 61cb3d6759SMichal Suchanek enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) && 62cb3d6759SMichal Suchanek security_ftr_enabled(SEC_FTR_BNDS_CHK_SPEC_BAR); 63cb3d6759SMichal Suchanek 64782e69efSJosh Poimboeuf if (!no_nospec && !cpu_mitigations_off()) 65cb3d6759SMichal Suchanek enable_barrier_nospec(enable); 66cb3d6759SMichal Suchanek } 67cb3d6759SMichal Suchanek 68cf175dc3SDiana Craciun static int __init handle_nospectre_v1(char *p) 69cf175dc3SDiana Craciun { 70cf175dc3SDiana Craciun no_nospec = true; 71cf175dc3SDiana Craciun 72cf175dc3SDiana Craciun return 0; 73cf175dc3SDiana Craciun } 74cf175dc3SDiana Craciun early_param("nospectre_v1", handle_nospectre_v1); 75cf175dc3SDiana Craciun 76cb3d6759SMichal Suchanek #ifdef CONFIG_DEBUG_FS 77cb3d6759SMichal Suchanek static int barrier_nospec_set(void *data, u64 val) 78cb3d6759SMichal Suchanek { 79cb3d6759SMichal Suchanek switch (val) { 80cb3d6759SMichal Suchanek case 0: 81cb3d6759SMichal Suchanek case 1: 82cb3d6759SMichal Suchanek break; 83cb3d6759SMichal Suchanek default: 84cb3d6759SMichal Suchanek return -EINVAL; 85cb3d6759SMichal Suchanek } 86cb3d6759SMichal Suchanek 87cb3d6759SMichal Suchanek if (!!val == !!barrier_nospec_enabled) 88cb3d6759SMichal Suchanek return 0; 89cb3d6759SMichal Suchanek 90cb3d6759SMichal Suchanek enable_barrier_nospec(!!val); 91cb3d6759SMichal Suchanek 92cb3d6759SMichal Suchanek return 0; 93cb3d6759SMichal Suchanek } 94cb3d6759SMichal Suchanek 95cb3d6759SMichal Suchanek static int barrier_nospec_get(void *data, u64 *val) 96cb3d6759SMichal Suchanek { 97cb3d6759SMichal Suchanek *val = barrier_nospec_enabled ? 1 : 0; 98cb3d6759SMichal Suchanek return 0; 99cb3d6759SMichal Suchanek } 100cb3d6759SMichal Suchanek 101090d5ab9SYueHaibing DEFINE_DEBUGFS_ATTRIBUTE(fops_barrier_nospec, barrier_nospec_get, 102090d5ab9SYueHaibing barrier_nospec_set, "%llu\n"); 103cb3d6759SMichal Suchanek 104cb3d6759SMichal Suchanek static __init int barrier_nospec_debugfs_init(void) 105cb3d6759SMichal Suchanek { 106090d5ab9SYueHaibing debugfs_create_file_unsafe("barrier_nospec", 0600, 107090d5ab9SYueHaibing powerpc_debugfs_root, NULL, 108cb3d6759SMichal Suchanek &fops_barrier_nospec); 109cb3d6759SMichal Suchanek return 0; 110cb3d6759SMichal Suchanek } 111cb3d6759SMichal Suchanek device_initcall(barrier_nospec_debugfs_init); 112398af571SMichael Ellerman 113398af571SMichael Ellerman static __init int security_feature_debugfs_init(void) 114398af571SMichael Ellerman { 115398af571SMichael Ellerman debugfs_create_x64("security_features", 0400, powerpc_debugfs_root, 1163b05a1e5SGeert Uytterhoeven &powerpc_security_features); 117398af571SMichael Ellerman return 0; 118398af571SMichael Ellerman } 119398af571SMichael Ellerman device_initcall(security_feature_debugfs_init); 120cb3d6759SMichal Suchanek #endif /* CONFIG_DEBUG_FS */ 121cb3d6759SMichal Suchanek 122d8f0e0b0SChristopher M. Riedl #if defined(CONFIG_PPC_FSL_BOOK3E) || defined(CONFIG_PPC_BOOK3S_64) 123f633a8adSDiana Craciun static int __init handle_nospectre_v2(char *p) 124f633a8adSDiana Craciun { 125f633a8adSDiana Craciun no_spectrev2 = true; 126f633a8adSDiana Craciun 127f633a8adSDiana Craciun return 0; 128f633a8adSDiana Craciun } 129f633a8adSDiana Craciun early_param("nospectre_v2", handle_nospectre_v2); 130d8f0e0b0SChristopher M. Riedl #endif /* CONFIG_PPC_FSL_BOOK3E || CONFIG_PPC_BOOK3S_64 */ 131d8f0e0b0SChristopher M. Riedl 132d8f0e0b0SChristopher M. Riedl #ifdef CONFIG_PPC_FSL_BOOK3E 133f633a8adSDiana Craciun void setup_spectre_v2(void) 134f633a8adSDiana Craciun { 135782e69efSJosh Poimboeuf if (no_spectrev2 || cpu_mitigations_off()) 136f633a8adSDiana Craciun do_btb_flush_fixups(); 137f633a8adSDiana Craciun else 138f633a8adSDiana Craciun btb_flush_enabled = true; 139f633a8adSDiana Craciun } 140f633a8adSDiana Craciun #endif /* CONFIG_PPC_FSL_BOOK3E */ 141f633a8adSDiana Craciun 142406d2b6aSDiana Craciun #ifdef CONFIG_PPC_BOOK3S_64 1438ad33041SMichael Ellerman ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, char *buf) 1448ad33041SMichael Ellerman { 145ff348355SMichael Ellerman bool thread_priv; 146ff348355SMichael Ellerman 147ff348355SMichael Ellerman thread_priv = security_ftr_enabled(SEC_FTR_L1D_THREAD_PRIV); 148ff348355SMichael Ellerman 1494e706af3SGustavo L. F. Walbon if (rfi_flush) { 150ff348355SMichael Ellerman struct seq_buf s; 151ff348355SMichael Ellerman seq_buf_init(&s, buf, PAGE_SIZE - 1); 152ff348355SMichael Ellerman 1534e706af3SGustavo L. F. Walbon seq_buf_printf(&s, "Mitigation: RFI Flush"); 154ff348355SMichael Ellerman if (thread_priv) 1554e706af3SGustavo L. F. Walbon seq_buf_printf(&s, ", L1D private per thread"); 156ff348355SMichael Ellerman 157ff348355SMichael Ellerman seq_buf_printf(&s, "\n"); 158ff348355SMichael Ellerman 159ff348355SMichael Ellerman return s.len; 160ff348355SMichael Ellerman } 161ff348355SMichael Ellerman 1624e706af3SGustavo L. F. Walbon if (thread_priv) 1634e706af3SGustavo L. F. Walbon return sprintf(buf, "Vulnerable: L1D private per thread\n"); 1644e706af3SGustavo L. F. Walbon 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 } 1718e6b6da9SAnthony Steinhauser 1728e6b6da9SAnthony Steinhauser ssize_t cpu_show_l1tf(struct device *dev, struct device_attribute *attr, char *buf) 1738e6b6da9SAnthony Steinhauser { 1748e6b6da9SAnthony Steinhauser return cpu_show_meltdown(dev, attr, buf); 1758e6b6da9SAnthony Steinhauser } 176406d2b6aSDiana Craciun #endif 17756986016SMichael Ellerman 17856986016SMichael Ellerman ssize_t cpu_show_spectre_v1(struct device *dev, struct device_attribute *attr, char *buf) 17956986016SMichael Ellerman { 1806d44acaeSMichael Ellerman struct seq_buf s; 18156986016SMichael Ellerman 1826d44acaeSMichael Ellerman seq_buf_init(&s, buf, PAGE_SIZE - 1); 1836d44acaeSMichael Ellerman 1846d44acaeSMichael Ellerman if (security_ftr_enabled(SEC_FTR_BNDS_CHK_SPEC_BAR)) { 185a3775145SMichal Suchanek if (barrier_nospec_enabled) 1866d44acaeSMichael Ellerman seq_buf_printf(&s, "Mitigation: __user pointer sanitization"); 1876d44acaeSMichael Ellerman else 1886d44acaeSMichael Ellerman seq_buf_printf(&s, "Vulnerable"); 189a3775145SMichal Suchanek 1906d44acaeSMichael Ellerman if (security_ftr_enabled(SEC_FTR_SPEC_BAR_ORI31)) 1916d44acaeSMichael Ellerman seq_buf_printf(&s, ", ori31 speculation barrier enabled"); 1926d44acaeSMichael Ellerman 1936d44acaeSMichael Ellerman seq_buf_printf(&s, "\n"); 1946d44acaeSMichael Ellerman } else 1956d44acaeSMichael Ellerman seq_buf_printf(&s, "Not affected\n"); 1966d44acaeSMichael Ellerman 1976d44acaeSMichael Ellerman return s.len; 19856986016SMichael Ellerman } 199d6fbe1c5SMichael Ellerman 200d6fbe1c5SMichael Ellerman ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr, char *buf) 201d6fbe1c5SMichael Ellerman { 202d6fbe1c5SMichael Ellerman struct seq_buf s; 2036d44acaeSMichael Ellerman bool bcs, ccd; 204d6fbe1c5SMichael Ellerman 205d6fbe1c5SMichael Ellerman seq_buf_init(&s, buf, PAGE_SIZE - 1); 206d6fbe1c5SMichael Ellerman 207d6fbe1c5SMichael Ellerman bcs = security_ftr_enabled(SEC_FTR_BCCTRL_SERIALISED); 208d6fbe1c5SMichael Ellerman ccd = security_ftr_enabled(SEC_FTR_COUNT_CACHE_DISABLED); 209d6fbe1c5SMichael Ellerman 21092edf8dfSMichael Ellerman if (bcs || ccd) { 211d6fbe1c5SMichael Ellerman seq_buf_printf(&s, "Mitigation: "); 212d6fbe1c5SMichael Ellerman 21392edf8dfSMichael Ellerman if (bcs) 214d6fbe1c5SMichael Ellerman seq_buf_printf(&s, "Indirect branch serialisation (kernel only)"); 215d6fbe1c5SMichael Ellerman 21692edf8dfSMichael Ellerman if (bcs && ccd) 217ee13cb24SMichael Ellerman seq_buf_printf(&s, ", "); 21892edf8dfSMichael Ellerman 21992edf8dfSMichael Ellerman if (ccd) 220ee13cb24SMichael Ellerman seq_buf_printf(&s, "Indirect branch cache disabled"); 22139e72bf9SMichael Ellerman 2221026798cSNicholas Piggin } else if (count_cache_flush_type != BRANCH_CACHE_FLUSH_NONE) { 22392edf8dfSMichael Ellerman seq_buf_printf(&s, "Mitigation: Software count cache flush"); 224ee13cb24SMichael Ellerman 2251026798cSNicholas Piggin if (count_cache_flush_type == BRANCH_CACHE_FLUSH_HW) 226ee13cb24SMichael Ellerman seq_buf_printf(&s, " (hardware accelerated)"); 22739e72bf9SMichael Ellerman 228dfa88658SDiana Craciun } else if (btb_flush_enabled) { 229dfa88658SDiana Craciun seq_buf_printf(&s, "Mitigation: Branch predictor state flush"); 230dfa88658SDiana Craciun } else { 231d6fbe1c5SMichael Ellerman seq_buf_printf(&s, "Vulnerable"); 232dfa88658SDiana Craciun } 233d6fbe1c5SMichael Ellerman 234*4d24e21cSNicholas Piggin if (bcs || ccd || count_cache_flush_type != BRANCH_CACHE_FLUSH_NONE) { 235*4d24e21cSNicholas Piggin if (link_stack_flush_type != BRANCH_CACHE_FLUSH_NONE) 236*4d24e21cSNicholas Piggin seq_buf_printf(&s, ", Software link stack flush"); 237*4d24e21cSNicholas Piggin if (link_stack_flush_type == BRANCH_CACHE_FLUSH_HW) 238*4d24e21cSNicholas Piggin seq_buf_printf(&s, " (hardware accelerated)"); 239*4d24e21cSNicholas Piggin } 240*4d24e21cSNicholas Piggin 241d6fbe1c5SMichael Ellerman seq_buf_printf(&s, "\n"); 242d6fbe1c5SMichael Ellerman 243d6fbe1c5SMichael Ellerman return s.len; 244d6fbe1c5SMichael Ellerman } 245a048a07dSNicholas Piggin 2466453b532SDiana Craciun #ifdef CONFIG_PPC_BOOK3S_64 247a048a07dSNicholas Piggin /* 248a048a07dSNicholas Piggin * Store-forwarding barrier support. 249a048a07dSNicholas Piggin */ 250a048a07dSNicholas Piggin 251a048a07dSNicholas Piggin static enum stf_barrier_type stf_enabled_flush_types; 252a048a07dSNicholas Piggin static bool no_stf_barrier; 253a048a07dSNicholas Piggin bool stf_barrier; 254a048a07dSNicholas Piggin 255a048a07dSNicholas Piggin static int __init handle_no_stf_barrier(char *p) 256a048a07dSNicholas Piggin { 257a048a07dSNicholas Piggin pr_info("stf-barrier: disabled on command line."); 258a048a07dSNicholas Piggin no_stf_barrier = true; 259a048a07dSNicholas Piggin return 0; 260a048a07dSNicholas Piggin } 261a048a07dSNicholas Piggin 262a048a07dSNicholas Piggin early_param("no_stf_barrier", handle_no_stf_barrier); 263a048a07dSNicholas Piggin 264a048a07dSNicholas Piggin /* This is the generic flag used by other architectures */ 265a048a07dSNicholas Piggin static int __init handle_ssbd(char *p) 266a048a07dSNicholas Piggin { 267a048a07dSNicholas Piggin if (!p || strncmp(p, "auto", 5) == 0 || strncmp(p, "on", 2) == 0 ) { 268a048a07dSNicholas Piggin /* Until firmware tells us, we have the barrier with auto */ 269a048a07dSNicholas Piggin return 0; 270a048a07dSNicholas Piggin } else if (strncmp(p, "off", 3) == 0) { 271a048a07dSNicholas Piggin handle_no_stf_barrier(NULL); 272a048a07dSNicholas Piggin return 0; 273a048a07dSNicholas Piggin } else 274a048a07dSNicholas Piggin return 1; 275a048a07dSNicholas Piggin 276a048a07dSNicholas Piggin return 0; 277a048a07dSNicholas Piggin } 278a048a07dSNicholas Piggin early_param("spec_store_bypass_disable", handle_ssbd); 279a048a07dSNicholas Piggin 280a048a07dSNicholas Piggin /* This is the generic flag used by other architectures */ 281a048a07dSNicholas Piggin static int __init handle_no_ssbd(char *p) 282a048a07dSNicholas Piggin { 283a048a07dSNicholas Piggin handle_no_stf_barrier(NULL); 284a048a07dSNicholas Piggin return 0; 285a048a07dSNicholas Piggin } 286a048a07dSNicholas Piggin early_param("nospec_store_bypass_disable", handle_no_ssbd); 287a048a07dSNicholas Piggin 288a048a07dSNicholas Piggin static void stf_barrier_enable(bool enable) 289a048a07dSNicholas Piggin { 290a048a07dSNicholas Piggin if (enable) 291a048a07dSNicholas Piggin do_stf_barrier_fixups(stf_enabled_flush_types); 292a048a07dSNicholas Piggin else 293a048a07dSNicholas Piggin do_stf_barrier_fixups(STF_BARRIER_NONE); 294a048a07dSNicholas Piggin 295a048a07dSNicholas Piggin stf_barrier = enable; 296a048a07dSNicholas Piggin } 297a048a07dSNicholas Piggin 298a048a07dSNicholas Piggin void setup_stf_barrier(void) 299a048a07dSNicholas Piggin { 300a048a07dSNicholas Piggin enum stf_barrier_type type; 301a048a07dSNicholas Piggin bool enable, hv; 302a048a07dSNicholas Piggin 303a048a07dSNicholas Piggin hv = cpu_has_feature(CPU_FTR_HVMODE); 304a048a07dSNicholas Piggin 305a048a07dSNicholas Piggin /* Default to fallback in case fw-features are not available */ 306a048a07dSNicholas Piggin if (cpu_has_feature(CPU_FTR_ARCH_300)) 307a048a07dSNicholas Piggin type = STF_BARRIER_EIEIO; 308a048a07dSNicholas Piggin else if (cpu_has_feature(CPU_FTR_ARCH_207S)) 309a048a07dSNicholas Piggin type = STF_BARRIER_SYNC_ORI; 310a048a07dSNicholas Piggin else if (cpu_has_feature(CPU_FTR_ARCH_206)) 311a048a07dSNicholas Piggin type = STF_BARRIER_FALLBACK; 312a048a07dSNicholas Piggin else 313a048a07dSNicholas Piggin type = STF_BARRIER_NONE; 314a048a07dSNicholas Piggin 315a048a07dSNicholas Piggin enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) && 316a048a07dSNicholas Piggin (security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR) || 317a048a07dSNicholas Piggin (security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) && hv)); 318a048a07dSNicholas Piggin 319a048a07dSNicholas Piggin if (type == STF_BARRIER_FALLBACK) { 320a048a07dSNicholas Piggin pr_info("stf-barrier: fallback barrier available\n"); 321a048a07dSNicholas Piggin } else if (type == STF_BARRIER_SYNC_ORI) { 322a048a07dSNicholas Piggin pr_info("stf-barrier: hwsync barrier available\n"); 323a048a07dSNicholas Piggin } else if (type == STF_BARRIER_EIEIO) { 324a048a07dSNicholas Piggin pr_info("stf-barrier: eieio barrier available\n"); 325a048a07dSNicholas Piggin } 326a048a07dSNicholas Piggin 327a048a07dSNicholas Piggin stf_enabled_flush_types = type; 328a048a07dSNicholas Piggin 329782e69efSJosh Poimboeuf if (!no_stf_barrier && !cpu_mitigations_off()) 330a048a07dSNicholas Piggin stf_barrier_enable(enable); 331a048a07dSNicholas Piggin } 332a048a07dSNicholas Piggin 333a048a07dSNicholas Piggin ssize_t cpu_show_spec_store_bypass(struct device *dev, struct device_attribute *attr, char *buf) 334a048a07dSNicholas Piggin { 335a048a07dSNicholas Piggin if (stf_barrier && stf_enabled_flush_types != STF_BARRIER_NONE) { 336a048a07dSNicholas Piggin const char *type; 337a048a07dSNicholas Piggin switch (stf_enabled_flush_types) { 338a048a07dSNicholas Piggin case STF_BARRIER_EIEIO: 339a048a07dSNicholas Piggin type = "eieio"; 340a048a07dSNicholas Piggin break; 341a048a07dSNicholas Piggin case STF_BARRIER_SYNC_ORI: 342a048a07dSNicholas Piggin type = "hwsync"; 343a048a07dSNicholas Piggin break; 344a048a07dSNicholas Piggin case STF_BARRIER_FALLBACK: 345a048a07dSNicholas Piggin type = "fallback"; 346a048a07dSNicholas Piggin break; 347a048a07dSNicholas Piggin default: 348a048a07dSNicholas Piggin type = "unknown"; 349a048a07dSNicholas Piggin } 350a048a07dSNicholas Piggin return sprintf(buf, "Mitigation: Kernel entry/exit barrier (%s)\n", type); 351a048a07dSNicholas Piggin } 352a048a07dSNicholas Piggin 353a048a07dSNicholas Piggin if (!security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) && 354a048a07dSNicholas Piggin !security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR)) 355a048a07dSNicholas Piggin return sprintf(buf, "Not affected\n"); 356a048a07dSNicholas Piggin 357a048a07dSNicholas Piggin return sprintf(buf, "Vulnerable\n"); 358a048a07dSNicholas Piggin } 359a048a07dSNicholas Piggin 360d93e5e2dSMichael Ellerman static int ssb_prctl_get(struct task_struct *task) 361d93e5e2dSMichael Ellerman { 362d93e5e2dSMichael Ellerman if (stf_enabled_flush_types == STF_BARRIER_NONE) 363d93e5e2dSMichael Ellerman /* 364d93e5e2dSMichael Ellerman * We don't have an explicit signal from firmware that we're 365d93e5e2dSMichael Ellerman * vulnerable or not, we only have certain CPU revisions that 366d93e5e2dSMichael Ellerman * are known to be vulnerable. 367d93e5e2dSMichael Ellerman * 368d93e5e2dSMichael Ellerman * We assume that if we're on another CPU, where the barrier is 369d93e5e2dSMichael Ellerman * NONE, then we are not vulnerable. 370d93e5e2dSMichael Ellerman */ 371d93e5e2dSMichael Ellerman return PR_SPEC_NOT_AFFECTED; 372d93e5e2dSMichael Ellerman else 373d93e5e2dSMichael Ellerman /* 374d93e5e2dSMichael Ellerman * If we do have a barrier type then we are vulnerable. The 375d93e5e2dSMichael Ellerman * barrier is not a global or per-process mitigation, so the 376d93e5e2dSMichael Ellerman * only value we can report here is PR_SPEC_ENABLE, which 377d93e5e2dSMichael Ellerman * appears as "vulnerable" in /proc. 378d93e5e2dSMichael Ellerman */ 379d93e5e2dSMichael Ellerman return PR_SPEC_ENABLE; 380d93e5e2dSMichael Ellerman 381d93e5e2dSMichael Ellerman return -EINVAL; 382d93e5e2dSMichael Ellerman } 383d93e5e2dSMichael Ellerman 384d93e5e2dSMichael Ellerman int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which) 385d93e5e2dSMichael Ellerman { 386d93e5e2dSMichael Ellerman switch (which) { 387d93e5e2dSMichael Ellerman case PR_SPEC_STORE_BYPASS: 388d93e5e2dSMichael Ellerman return ssb_prctl_get(task); 389d93e5e2dSMichael Ellerman default: 390d93e5e2dSMichael Ellerman return -ENODEV; 391d93e5e2dSMichael Ellerman } 392d93e5e2dSMichael Ellerman } 393d93e5e2dSMichael Ellerman 394a048a07dSNicholas Piggin #ifdef CONFIG_DEBUG_FS 395a048a07dSNicholas Piggin static int stf_barrier_set(void *data, u64 val) 396a048a07dSNicholas Piggin { 397a048a07dSNicholas Piggin bool enable; 398a048a07dSNicholas Piggin 399a048a07dSNicholas Piggin if (val == 1) 400a048a07dSNicholas Piggin enable = true; 401a048a07dSNicholas Piggin else if (val == 0) 402a048a07dSNicholas Piggin enable = false; 403a048a07dSNicholas Piggin else 404a048a07dSNicholas Piggin return -EINVAL; 405a048a07dSNicholas Piggin 406a048a07dSNicholas Piggin /* Only do anything if we're changing state */ 407a048a07dSNicholas Piggin if (enable != stf_barrier) 408a048a07dSNicholas Piggin stf_barrier_enable(enable); 409a048a07dSNicholas Piggin 410a048a07dSNicholas Piggin return 0; 411a048a07dSNicholas Piggin } 412a048a07dSNicholas Piggin 413a048a07dSNicholas Piggin static int stf_barrier_get(void *data, u64 *val) 414a048a07dSNicholas Piggin { 415a048a07dSNicholas Piggin *val = stf_barrier ? 1 : 0; 416a048a07dSNicholas Piggin return 0; 417a048a07dSNicholas Piggin } 418a048a07dSNicholas Piggin 419090d5ab9SYueHaibing DEFINE_DEBUGFS_ATTRIBUTE(fops_stf_barrier, stf_barrier_get, stf_barrier_set, 420090d5ab9SYueHaibing "%llu\n"); 421a048a07dSNicholas Piggin 422a048a07dSNicholas Piggin static __init int stf_barrier_debugfs_init(void) 423a048a07dSNicholas Piggin { 424090d5ab9SYueHaibing debugfs_create_file_unsafe("stf_barrier", 0600, powerpc_debugfs_root, 425090d5ab9SYueHaibing NULL, &fops_stf_barrier); 426a048a07dSNicholas Piggin return 0; 427a048a07dSNicholas Piggin } 428a048a07dSNicholas Piggin device_initcall(stf_barrier_debugfs_init); 429a048a07dSNicholas Piggin #endif /* CONFIG_DEBUG_FS */ 430ee13cb24SMichael Ellerman 431c0036549SNicholas Piggin static void update_branch_cache_flush(void) 432ee13cb24SMichael Ellerman { 433c0036549SNicholas Piggin #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE 434c0036549SNicholas Piggin // This controls the branch from guest_exit_cont to kvm_flush_link_stack 435c0036549SNicholas Piggin if (link_stack_flush_type == BRANCH_CACHE_FLUSH_NONE) { 436c0036549SNicholas Piggin patch_instruction_site(&patch__call_kvm_flush_link_stack, 437c0036549SNicholas Piggin ppc_inst(PPC_INST_NOP)); 438c0036549SNicholas Piggin } else { 439*4d24e21cSNicholas Piggin // Could use HW flush, but that could also flush count cache 440c0036549SNicholas Piggin patch_branch_site(&patch__call_kvm_flush_link_stack, 441c0036549SNicholas Piggin (u64)&kvm_flush_link_stack, BRANCH_SET_LINK); 442c0036549SNicholas Piggin } 443c0036549SNicholas Piggin #endif 444c0036549SNicholas Piggin 445c0036549SNicholas Piggin // This controls the branch from _switch to flush_branch_caches 446c0036549SNicholas Piggin if (count_cache_flush_type == BRANCH_CACHE_FLUSH_NONE && 447c0036549SNicholas Piggin link_stack_flush_type == BRANCH_CACHE_FLUSH_NONE) { 448c0036549SNicholas Piggin patch_instruction_site(&patch__call_flush_branch_caches, 449c0036549SNicholas Piggin ppc_inst(PPC_INST_NOP)); 450*4d24e21cSNicholas Piggin } else if (count_cache_flush_type == BRANCH_CACHE_FLUSH_HW && 451*4d24e21cSNicholas Piggin link_stack_flush_type == BRANCH_CACHE_FLUSH_HW) { 452*4d24e21cSNicholas Piggin patch_instruction_site(&patch__call_flush_branch_caches, 453*4d24e21cSNicholas Piggin ppc_inst(PPC_INST_BCCTR_FLUSH)); 454c0036549SNicholas Piggin } else { 455c0036549SNicholas Piggin patch_branch_site(&patch__call_flush_branch_caches, 456c0036549SNicholas Piggin (u64)&flush_branch_caches, BRANCH_SET_LINK); 457c0036549SNicholas Piggin 458c0036549SNicholas Piggin // If we just need to flush the link stack, early return 459c0036549SNicholas Piggin if (count_cache_flush_type == BRANCH_CACHE_FLUSH_NONE) { 460c0036549SNicholas Piggin patch_instruction_site(&patch__flush_link_stack_return, 461c0036549SNicholas Piggin ppc_inst(PPC_INST_BLR)); 462c0036549SNicholas Piggin 463c0036549SNicholas Piggin // If we have flush instruction, early return 464c0036549SNicholas Piggin } else if (count_cache_flush_type == BRANCH_CACHE_FLUSH_HW) { 465c0036549SNicholas Piggin patch_instruction_site(&patch__flush_count_cache_return, 466c0036549SNicholas Piggin ppc_inst(PPC_INST_BLR)); 467c0036549SNicholas Piggin } 468c0036549SNicholas Piggin } 46939e72bf9SMichael Ellerman } 47039e72bf9SMichael Ellerman 4711026798cSNicholas Piggin static void toggle_branch_cache_flush(bool enable) 47239e72bf9SMichael Ellerman { 473c0036549SNicholas Piggin if (!enable || !security_ftr_enabled(SEC_FTR_FLUSH_COUNT_CACHE)) { 474c0036549SNicholas Piggin if (count_cache_flush_type != BRANCH_CACHE_FLUSH_NONE) 475c0036549SNicholas Piggin count_cache_flush_type = BRANCH_CACHE_FLUSH_NONE; 47639e72bf9SMichael Ellerman 477c0036549SNicholas Piggin pr_info("count-cache-flush: flush disabled.\n"); 478c0036549SNicholas Piggin } else { 479c0036549SNicholas Piggin if (security_ftr_enabled(SEC_FTR_BCCTR_FLUSH_ASSIST)) { 4801026798cSNicholas Piggin count_cache_flush_type = BRANCH_CACHE_FLUSH_HW; 4811afe00c7SNicholas Piggin pr_info("count-cache-flush: hardware flush enabled.\n"); 482c0036549SNicholas Piggin } else { 483c0036549SNicholas Piggin count_cache_flush_type = BRANCH_CACHE_FLUSH_SW; 484c0036549SNicholas Piggin pr_info("count-cache-flush: software flush enabled.\n"); 485c0036549SNicholas Piggin } 486c0036549SNicholas Piggin } 487c0036549SNicholas Piggin 488c0036549SNicholas Piggin if (!enable || !security_ftr_enabled(SEC_FTR_FLUSH_LINK_STACK)) { 489c0036549SNicholas Piggin if (link_stack_flush_type != BRANCH_CACHE_FLUSH_NONE) 490c0036549SNicholas Piggin link_stack_flush_type = BRANCH_CACHE_FLUSH_NONE; 491c0036549SNicholas Piggin 492c0036549SNicholas Piggin pr_info("link-stack-flush: flush disabled.\n"); 493c0036549SNicholas Piggin } else { 494*4d24e21cSNicholas Piggin if (security_ftr_enabled(SEC_FTR_BCCTR_LINK_FLUSH_ASSIST)) { 495*4d24e21cSNicholas Piggin link_stack_flush_type = BRANCH_CACHE_FLUSH_HW; 496*4d24e21cSNicholas Piggin pr_info("link-stack-flush: hardware flush enabled.\n"); 497*4d24e21cSNicholas Piggin } else { 498c0036549SNicholas Piggin link_stack_flush_type = BRANCH_CACHE_FLUSH_SW; 499c0036549SNicholas Piggin pr_info("link-stack-flush: software flush enabled.\n"); 500c0036549SNicholas Piggin } 501*4d24e21cSNicholas Piggin } 502c0036549SNicholas Piggin 503c0036549SNicholas Piggin update_branch_cache_flush(); 504ee13cb24SMichael Ellerman } 505ee13cb24SMichael Ellerman 506ee13cb24SMichael Ellerman void setup_count_cache_flush(void) 507ee13cb24SMichael Ellerman { 508d8f0e0b0SChristopher M. Riedl bool enable = true; 509d8f0e0b0SChristopher M. Riedl 510d8f0e0b0SChristopher M. Riedl if (no_spectrev2 || cpu_mitigations_off()) { 511d8f0e0b0SChristopher M. Riedl if (security_ftr_enabled(SEC_FTR_BCCTRL_SERIALISED) || 512d8f0e0b0SChristopher M. Riedl security_ftr_enabled(SEC_FTR_COUNT_CACHE_DISABLED)) 51339e72bf9SMichael Ellerman pr_warn("Spectre v2 mitigations not fully under software control, can't disable\n"); 514d8f0e0b0SChristopher M. Riedl 515d8f0e0b0SChristopher M. Riedl enable = false; 516d8f0e0b0SChristopher M. Riedl } 517d8f0e0b0SChristopher M. Riedl 51839e72bf9SMichael Ellerman /* 51939e72bf9SMichael Ellerman * There's no firmware feature flag/hypervisor bit to tell us we need to 52039e72bf9SMichael Ellerman * flush the link stack on context switch. So we set it here if we see 52139e72bf9SMichael Ellerman * either of the Spectre v2 mitigations that aim to protect userspace. 52239e72bf9SMichael Ellerman */ 52339e72bf9SMichael Ellerman if (security_ftr_enabled(SEC_FTR_COUNT_CACHE_DISABLED) || 52439e72bf9SMichael Ellerman security_ftr_enabled(SEC_FTR_FLUSH_COUNT_CACHE)) 52539e72bf9SMichael Ellerman security_ftr_set(SEC_FTR_FLUSH_LINK_STACK); 52639e72bf9SMichael Ellerman 5271026798cSNicholas Piggin toggle_branch_cache_flush(enable); 528ee13cb24SMichael Ellerman } 529ee13cb24SMichael Ellerman 530ee13cb24SMichael Ellerman #ifdef CONFIG_DEBUG_FS 531ee13cb24SMichael Ellerman static int count_cache_flush_set(void *data, u64 val) 532ee13cb24SMichael Ellerman { 533ee13cb24SMichael Ellerman bool enable; 534ee13cb24SMichael Ellerman 535ee13cb24SMichael Ellerman if (val == 1) 536ee13cb24SMichael Ellerman enable = true; 537ee13cb24SMichael Ellerman else if (val == 0) 538ee13cb24SMichael Ellerman enable = false; 539ee13cb24SMichael Ellerman else 540ee13cb24SMichael Ellerman return -EINVAL; 541ee13cb24SMichael Ellerman 5421026798cSNicholas Piggin toggle_branch_cache_flush(enable); 543ee13cb24SMichael Ellerman 544ee13cb24SMichael Ellerman return 0; 545ee13cb24SMichael Ellerman } 546ee13cb24SMichael Ellerman 547ee13cb24SMichael Ellerman static int count_cache_flush_get(void *data, u64 *val) 548ee13cb24SMichael Ellerman { 5491026798cSNicholas Piggin if (count_cache_flush_type == BRANCH_CACHE_FLUSH_NONE) 550ee13cb24SMichael Ellerman *val = 0; 551ee13cb24SMichael Ellerman else 552ee13cb24SMichael Ellerman *val = 1; 553ee13cb24SMichael Ellerman 554ee13cb24SMichael Ellerman return 0; 555ee13cb24SMichael Ellerman } 556ee13cb24SMichael Ellerman 557090d5ab9SYueHaibing DEFINE_DEBUGFS_ATTRIBUTE(fops_count_cache_flush, count_cache_flush_get, 558ee13cb24SMichael Ellerman count_cache_flush_set, "%llu\n"); 559ee13cb24SMichael Ellerman 560ee13cb24SMichael Ellerman static __init int count_cache_flush_debugfs_init(void) 561ee13cb24SMichael Ellerman { 562090d5ab9SYueHaibing debugfs_create_file_unsafe("count_cache_flush", 0600, 563090d5ab9SYueHaibing powerpc_debugfs_root, NULL, 564090d5ab9SYueHaibing &fops_count_cache_flush); 565ee13cb24SMichael Ellerman return 0; 566ee13cb24SMichael Ellerman } 567ee13cb24SMichael Ellerman device_initcall(count_cache_flush_debugfs_init); 568ee13cb24SMichael Ellerman #endif /* CONFIG_DEBUG_FS */ 5696453b532SDiana Craciun #endif /* CONFIG_PPC_BOOK3S_64 */ 570