[RFC PATCH 5/6] powerpc/dexcr: Add sysctl entry for SBHE system override

Benjamin Gray bgray at linux.ibm.com
Mon Oct 9 16:54:05 AEDT 2023


The DEXCR Speculative Branch Hint Enable (SBHE) aspect controls whether
the hints provided by BO field of Branch instructions are obeyed during
speculative execution.

SBHE behaviour per ISA 3.1B:

0:	The hints provided by BO field of Branch instructions may be
	ignored during speculative execution

1:	The hints provided by BO field of Branch instructions are obeyed
	during speculative execution

Add a sysctl entry to allow changing this aspect globally in the system
at runtime:

	/proc/sys/kernel/speculative_branch_hint_enable

Three values are supported:

-1:	Disable DEXCR SBHE sysctl override
 0:	Override and set DEXCR[SBHE] aspect to 0
 1:	Override and set DEXCR[SBHE] aspect to 1

Internally, introduces a mechanism to apply arbitrary system wide
overrides on top of the prctl() config.

Signed-off-by: Benjamin Gray <bgray at linux.ibm.com>
---
 arch/powerpc/include/asm/processor.h |  8 +--
 arch/powerpc/kernel/dexcr.c          | 85 ++++++++++++++++++++++++++++
 2 files changed, 89 insertions(+), 4 deletions(-)

diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index a9d83621dfad..e7b732efb968 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -461,14 +461,14 @@ int exit_vmx_usercopy(void);
 int enter_vmx_ops(void);
 void *exit_vmx_ops(void *dest);
 
-static inline unsigned long get_thread_dexcr(struct thread_struct const *thread)
-{
 #ifdef CONFIG_PPC_BOOK3S_64
-	return thread->dexcr_enabled;
+unsigned long get_thread_dexcr(struct thread_struct const *thread);
 #else
+static inline unsigned long get_thread_dexcr(struct thread_struct const *thread)
+{
 	return 0;
-#endif
 }
+#endif
 
 #endif /* __KERNEL__ */
 #endif /* __ASSEMBLY__ */
diff --git a/arch/powerpc/kernel/dexcr.c b/arch/powerpc/kernel/dexcr.c
index db663ce7b3ce..e790f76787db 100644
--- a/arch/powerpc/kernel/dexcr.c
+++ b/arch/powerpc/kernel/dexcr.c
@@ -1,7 +1,9 @@
 #include <linux/capability.h>
+#include <linux/cpu.h>
 #include <linux/init.h>
 #include <linux/prctl.h>
 #include <linux/sched.h>
+#include <linux/sysctl.h>
 
 #include <asm/cpu_has_feature.h>
 #include <asm/cputable.h>
@@ -16,6 +18,8 @@
 
 static unsigned long dexcr_supported __ro_after_init = 0;
 
+static int spec_branch_hint_enable = -1;
+
 static int __init dexcr_init(void)
 {
 	if (!early_cpu_has_feature(CPU_FTR_ARCH_31))
@@ -37,6 +41,35 @@ static int __init dexcr_init(void)
 }
 early_initcall(dexcr_init);
 
+unsigned long get_thread_dexcr(struct thread_struct const *thread)
+{
+	unsigned long dexcr = thread->dexcr_enabled;
+
+	/* 
+	 * spec_branch_hint_enable may be written to concurrently via sysctl.
+	 * The sysctl handler is careful to use WRITE_ONCE, so we avoid
+	 * tearing/different values with READ_ONCE 
+	 */
+	switch (READ_ONCE(spec_branch_hint_enable)) {
+	case 0:
+		dexcr &= ~DEXCR_PR_SBHE;
+		break;
+	case 1:
+		dexcr |= DEXCR_PR_SBHE;
+		break;
+	}
+
+	return dexcr;
+}
+
+static void update_dexcr_on_cpu(void *_info)
+{
+	/* ensure the spec_branch_hint_enable write propagated to this CPU */
+	smp_mb();
+
+	mtspr(SPRN_DEXCR, get_thread_dexcr(&current->thread));
+}
+
 static int prctl_to_aspect(unsigned long which, unsigned int *aspect)
 {
 	switch (which) {
@@ -126,3 +159,55 @@ int set_dexcr_prctl(struct task_struct *task, unsigned long which, unsigned long
 
 	return 0;
 }
+
+#ifdef CONFIG_SYSCTL
+
+static const int min_sysctl_val = -1;
+
+static int sysctl_dexcr_sbhe_handler(struct ctl_table *table, int write,
+				     void *buf, size_t *lenp, loff_t *ppos)
+{
+	int err = 0;
+	int prev;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	if (!cpu_has_feature(CPU_FTR_DEXCR_SBHE))
+		return -ENODEV;
+
+	prev = READ_ONCE(spec_branch_hint_enable);
+	
+	err = proc_dointvec_minmax(table, write, buf, lenp, ppos);
+	if (err)
+		return err;
+
+	if (spec_branch_hint_enable != prev && write)
+		on_each_cpu(update_dexcr_on_cpu, NULL, 1);
+
+	return 0;
+}
+
+static struct ctl_table dexcr_sbhe_ctl_table[] = {
+	{
+		.procname	= "speculative_branch_hint_enable",
+		.data		= &spec_branch_hint_enable,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= sysctl_dexcr_sbhe_handler,
+		.extra1		= (void *)&min_sysctl_val,
+		.extra2		= SYSCTL_ONE,
+	}
+};
+
+static int __init register_dexcr_aspects_sysctl(void)
+{
+	if (!early_cpu_has_feature(CPU_FTR_DEXCR_SBHE))
+		return -ENODEV;
+
+	register_sysctl("kernel", dexcr_sbhe_ctl_table);
+	return 0;
+}
+device_initcall(register_dexcr_aspects_sysctl);
+
+#endif /* CONFIG_SYSCTL */
-- 
2.41.0



More information about the Linuxppc-dev mailing list