[RFC,07/13] powerpc/dexcr: Add sysctl entry for SBHE system override

Message ID 20221128024458.46121-8-bgray@linux.ibm.com
State New
Headers
Series Add DEXCR support |

Commit Message

Benjamin Gray Nov. 28, 2022, 2:44 a.m. UTC
  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@linux.ibm.com>
---
 arch/powerpc/kernel/dexcr.c | 125 ++++++++++++++++++++++++++++++++++++
 1 file changed, 125 insertions(+)
  

Comments

Nicholas Piggin March 7, 2023, 5:30 a.m. UTC | #1
On Mon Nov 28, 2022 at 12:44 PM AEST, Benjamin Gray wrote:
> 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.

Why have an override for this, and not others?

Thanks,
Nick
  
Benjamin Gray March 7, 2023, 5:58 a.m. UTC | #2
On Tue, 2023-03-07 at 15:30 +1000, Nicholas Piggin wrote:
> On Mon Nov 28, 2022 at 12:44 PM AEST, Benjamin Gray wrote:
> > 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.
> 
> Why have an override for this, and not others?
> 

Should be in the commit message of course, but this aspect bleeds over
to other processes, so a user may wish to prevent all processes from
changing the value. The other aspects are probably only relevant to
their own process, though the implementation here should support
arbitrary system wide overrides.
  

Patch

diff --git a/arch/powerpc/kernel/dexcr.c b/arch/powerpc/kernel/dexcr.c
index 9290beed722a..8239bcc92026 100644
--- a/arch/powerpc/kernel/dexcr.c
+++ b/arch/powerpc/kernel/dexcr.c
@@ -1,8 +1,11 @@ 
 #include <linux/cache.h>
 #include <linux/capability.h>
+#include <linux/cpu.h>
 #include <linux/init.h>
 #include <linux/prctl.h>
 #include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/sysctl.h>
 
 #include <asm/cpu_has_feature.h>
 #include <asm/cputable.h>
@@ -18,6 +21,58 @@ 
 #define DEXCR_PRCTL_EDITABLE (DEXCR_PRO_SBHE | DEXCR_PRO_IBRTPD | \
 			      DEXCR_PRO_SRAPD | DEXCR_PRO_NPHIE)
 
+/*
+ * Lock to protect system DEXCR override from concurrent updates.
+ * RCU semantics: writers take lock, readers are unlocked.
+ * Writers ensure the memory update is atomic, readers read
+ * atomically.
+ */
+static DEFINE_SPINLOCK(dexcr_sys_enforced_write_lock);
+
+struct mask_override {
+	union {
+		struct {
+			unsigned int mask;
+			unsigned int override;
+		};
+
+		/* Raw access for atomic read/write */
+		unsigned long all;
+	};
+};
+
+static struct mask_override dexcr_sys_enforced;
+
+static int spec_branch_hint_enable = -1;
+
+static void update_userspace_system_dexcr(unsigned int pro_mask, int value)
+{
+	struct mask_override update = { .all = 0 };
+
+	switch (value) {
+	case -1:  /* Clear the mask bit, clear the override bit */
+		break;
+	case 0:  /* Set the mask bit, clear the override bit */
+		update.mask |= pro_mask;
+		break;
+	case 1:  /* Set the mask bit, set the override bit */
+		update.mask |= pro_mask;
+		update.override |= pro_mask;
+		break;
+	}
+
+	spin_lock(&dexcr_sys_enforced_write_lock);
+
+	/* Use the existing values for the non-updated bits */
+	update.mask |= dexcr_sys_enforced.mask & ~pro_mask;
+	update.override |= dexcr_sys_enforced.override & ~pro_mask;
+
+	/* Atomically update system enforced aspects */
+	WRITE_ONCE(dexcr_sys_enforced.all, update.all);
+
+	spin_unlock(&dexcr_sys_enforced_write_lock);
+}
+
 static int __init dexcr_init(void)
 {
 	if (!early_cpu_has_feature(CPU_FTR_ARCH_31))
@@ -25,6 +80,9 @@  static int __init dexcr_init(void)
 
 	mtspr(SPRN_DEXCR, DEFAULT_DEXCR);
 
+	if (early_cpu_has_feature(CPU_FTR_DEXCR_SBHE))
+		update_userspace_system_dexcr(DEXCR_PRO_SBHE, spec_branch_hint_enable);
+
 	return 0;
 }
 early_initcall(dexcr_init);
@@ -52,9 +110,15 @@  unsigned long get_thread_dexcr(struct thread_struct const *t)
 {
 	unsigned long dexcr = DEFAULT_DEXCR;
 
+	/* Atomically read enforced mask & override */
+	struct mask_override enforced = READ_ONCE(dexcr_sys_enforced);
+
 	/* Apply prctl overrides */
 	dexcr = (dexcr & ~t->dexcr_mask) | t->dexcr_override;
 
+	/* Apply system overrides */
+	dexcr = (dexcr & ~enforced.mask) | enforced.override;
+
 	return dexcr;
 }
 
@@ -176,3 +240,64 @@  int dexcr_prctl_set(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;
+	int prev = spec_branch_hint_enable;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	if (!cpu_has_feature(CPU_FTR_DEXCR_SBHE))
+		return -ENODEV;
+
+	err = proc_dointvec_minmax(table, write, buf, lenp, ppos);
+	if (err)
+		return err;
+
+	if (prev != spec_branch_hint_enable && write) {
+		update_userspace_system_dexcr(DEXCR_PRO_SBHE, spec_branch_hint_enable);
+		cpus_read_lock();
+		on_each_cpu(update_dexcr_on_cpu, NULL, 1);
+		cpus_read_unlock();
+	}
+
+	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 struct ctl_table dexcr_sbhe_ctl_root[] = {
+	{
+		.procname	= "kernel",
+		.mode		= 0555,
+		.child		= dexcr_sbhe_ctl_table,
+	},
+	{}
+};
+
+static int __init register_dexcr_aspects_sysctl(void)
+{
+	register_sysctl_table(dexcr_sbhe_ctl_root);
+	return 0;
+}
+device_initcall(register_dexcr_aspects_sysctl);
+
+#endif /* CONFIG_SYSCTL */