[RFC,V2,02/17] x86/fpu: Refactor arch_set_user_pkey_access() for PKS support
diff mbox series

Message ID 20200717072056.73134-3-ira.weiny@intel.com
State New
Headers show
Series
  • PKS: Add Protection Keys Supervisor (PKS) support
Related show

Commit Message

Ira Weiny July 17, 2020, 7:20 a.m. UTC
From: Fenghua Yu <fenghua.yu@intel.com>

Define a helper, get_new_pkr(), which will be used to support both
Protection Key User (PKU) and the new Protection Key for Supervisor
(PKS) in subsequent patches.

Co-developed-by: Ira Weiny <ira.weiny@intel.com>
Signed-off-by: Ira Weiny <ira.weiny@intel.com>
Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
---
 arch/x86/include/asm/pkeys.h |  2 ++
 arch/x86/kernel/fpu/xstate.c | 17 +++--------------
 arch/x86/mm/pkeys.c          | 28 ++++++++++++++++++++++++++++
 3 files changed, 33 insertions(+), 14 deletions(-)

Comments

Peter Zijlstra July 17, 2020, 8:54 a.m. UTC | #1
On Fri, Jul 17, 2020 at 12:20:41AM -0700, ira.weiny@intel.com wrote:
> +/*
> + * Get a new pkey register value from the user values specified.
> + *
> + * Kernel users use the same flags as user space:
> + *     PKEY_DISABLE_ACCESS
> + *     PKEY_DISABLE_WRITE
> + */
> +u32 get_new_pkr(u32 old_pkr, int pkey, unsigned long init_val)
> +{
> +	int pkey_shift = (pkey * PKR_BITS_PER_PKEY);
> +	u32 new_pkr_bits = 0;
> +
> +	/* Set the bits we need in the register:  */
> +	if (init_val & PKEY_DISABLE_ACCESS)
> +		new_pkr_bits |= PKR_AD_BIT;
> +	if (init_val & PKEY_DISABLE_WRITE)
> +		new_pkr_bits |= PKR_WD_BIT;
> +
> +	/* Shift the bits in to the correct place: */
> +	new_pkr_bits <<= pkey_shift;
> +
> +	/* Mask off any old bits in place: */
> +	old_pkr &= ~((PKR_AD_BIT | PKR_WD_BIT) << pkey_shift);
> +
> +	/* Return the old part along with the new part: */
> +	return old_pkr | new_pkr_bits;
> +}

This is unbelievable junk...

How about something like:

u32 update_pkey_reg(u32 pk_reg, int pkey, unsigned int flags)
{
	int pkey_shift = pkey * PKR_BITS_PER_PKEY;

	pk_reg &= ~(((1 << PKR_BITS_PER_PKEY) - 1) << pkey_shift);

	if (flags & PKEY_DISABLE_ACCESS)
		pk_reg |= PKR_AD_BIT << pkey_shift;
	if (flags & PKEY_DISABLE_WRITE)
		pk_reg |= PKR_WD_BIT << pkey_shift;

	return pk_reg;
}

Then we at least have a little clue wtf the thing does.. Yes I started
with a rename and then got annoyed at the implementation too.
Ira Weiny July 17, 2020, 8:52 p.m. UTC | #2
On Fri, Jul 17, 2020 at 10:54:42AM +0200, Peter Zijlstra wrote:
> On Fri, Jul 17, 2020 at 12:20:41AM -0700, ira.weiny@intel.com wrote:
> > +/*
> > + * Get a new pkey register value from the user values specified.
> > + *
> > + * Kernel users use the same flags as user space:
> > + *     PKEY_DISABLE_ACCESS
> > + *     PKEY_DISABLE_WRITE
> > + */
> > +u32 get_new_pkr(u32 old_pkr, int pkey, unsigned long init_val)
> > +{
> > +	int pkey_shift = (pkey * PKR_BITS_PER_PKEY);
> > +	u32 new_pkr_bits = 0;
> > +
> > +	/* Set the bits we need in the register:  */
> > +	if (init_val & PKEY_DISABLE_ACCESS)
> > +		new_pkr_bits |= PKR_AD_BIT;
> > +	if (init_val & PKEY_DISABLE_WRITE)
> > +		new_pkr_bits |= PKR_WD_BIT;
> > +
> > +	/* Shift the bits in to the correct place: */
> > +	new_pkr_bits <<= pkey_shift;
> > +
> > +	/* Mask off any old bits in place: */
> > +	old_pkr &= ~((PKR_AD_BIT | PKR_WD_BIT) << pkey_shift);
> > +
> > +	/* Return the old part along with the new part: */
> > +	return old_pkr | new_pkr_bits;
> > +}
> 
> This is unbelievable junk...
> 
> How about something like:
> 
> u32 update_pkey_reg(u32 pk_reg, int pkey, unsigned int flags)
> {
> 	int pkey_shift = pkey * PKR_BITS_PER_PKEY;
> 
> 	pk_reg &= ~(((1 << PKR_BITS_PER_PKEY) - 1) << pkey_shift);
> 
> 	if (flags & PKEY_DISABLE_ACCESS)
> 		pk_reg |= PKR_AD_BIT << pkey_shift;
> 	if (flags & PKEY_DISABLE_WRITE)
> 		pk_reg |= PKR_WD_BIT << pkey_shift;
> 
> 	return pk_reg;
> }
> 
> Then we at least have a little clue wtf the thing does.. Yes I started
> with a rename and then got annoyed at the implementation too.

On the code I think this is fair.  I've also updated the calling function to be
a bit cleaner as well.

However, I think the name 'update' is a bit misleading.  Here is the new
calling code:

...
        pkru = read_pkru();
	pkru = update_pkey_reg(pkru, pkey, init_val);
	write_pkru(pkru);
...


I think it is odd to have a function called update_pkey_reg() called right
before a write_pkru().  Can we call this update_pkey_value?  or just 'val'?
Because write_pkru() actually updates the register.

Thanks for the review,
Ira
Dave Hansen July 17, 2020, 10:36 p.m. UTC | #3
On 7/17/20 1:54 AM, Peter Zijlstra wrote:
> This is unbelievable junk...

Ouch!

This is from the original user pkeys implementation.

> How about something like:
> 
> u32 update_pkey_reg(u32 pk_reg, int pkey, unsigned int flags)
> {
> 	int pkey_shift = pkey * PKR_BITS_PER_PKEY;
> 
> 	pk_reg &= ~(((1 << PKR_BITS_PER_PKEY) - 1) << pkey_shift);
> 
> 	if (flags & PKEY_DISABLE_ACCESS)
> 		pk_reg |= PKR_AD_BIT << pkey_shift;
> 	if (flags & PKEY_DISABLE_WRITE)
> 		pk_reg |= PKR_WD_BIT << pkey_shift;
> 
> 	return pk_reg;
> }
> 
> Then we at least have a little clue wtf the thing does.. Yes I started
> with a rename and then got annoyed at the implementation too.

That's fine, if some comments get added.  It looks correct to me but
probably compiles down to pretty much the same thing as what was there.
 FWIW, I prefer the explicit masking off of two bit values to implicit
masking off with a mask generated from PKR_BITS_PER_PKEY.  It's
certainly more compact, but I usually don't fret over the lines of code.
Peter Zijlstra July 20, 2020, 9:13 a.m. UTC | #4
On Fri, Jul 17, 2020 at 03:36:12PM -0700, Dave Hansen wrote:
> On 7/17/20 1:54 AM, Peter Zijlstra wrote:
> > This is unbelievable junk...
> 
> Ouch!
> 
> This is from the original user pkeys implementation.

The thing I fell over most was new in this patch; the naming of that
function. It doesn't 'get' anything, nor does it allocate anything, so
'new' is out the window too.

> > How about something like:
> > 
> > u32 update_pkey_reg(u32 pk_reg, int pkey, unsigned int flags)
> > {
> > 	int pkey_shift = pkey * PKR_BITS_PER_PKEY;
> > 
> > 	pk_reg &= ~(((1 << PKR_BITS_PER_PKEY) - 1) << pkey_shift);
> > 
> > 	if (flags & PKEY_DISABLE_ACCESS)
> > 		pk_reg |= PKR_AD_BIT << pkey_shift;
> > 	if (flags & PKEY_DISABLE_WRITE)
> > 		pk_reg |= PKR_WD_BIT << pkey_shift;
> > 
> > 	return pk_reg;
> > }
> > 
> > Then we at least have a little clue wtf the thing does.. Yes I started
> > with a rename and then got annoyed at the implementation too.
> 
> That's fine, if some comments get added.

I'm not sure what you would want commented; the code is trivial.

> It looks correct to me but
> probably compiles down to pretty much the same thing as what was there.
>  FWIW, I prefer the explicit masking off of two bit values to implicit
> masking off with a mask generated from PKR_BITS_PER_PKEY.  It's
> certainly more compact, but I usually don't fret over the lines of code.

This way you're sure there are no bits missed. Both the shift and mask
use the same value.
Peter Zijlstra July 20, 2020, 9:14 a.m. UTC | #5
On Fri, Jul 17, 2020 at 01:52:55PM -0700, Ira Weiny wrote:
> On Fri, Jul 17, 2020 at 10:54:42AM +0200, Peter Zijlstra wrote:

> > Then we at least have a little clue wtf the thing does.. Yes I started
> > with a rename and then got annoyed at the implementation too.
> 
> On the code I think this is fair.  I've also updated the calling function to be
> a bit cleaner as well.
> 
> However, I think the name 'update' is a bit misleading.  Here is the new
> calling code:
> 
> ...
>         pkru = read_pkru();
> 	pkru = update_pkey_reg(pkru, pkey, init_val);
> 	write_pkru(pkru);
> ...
> 
> 
> I think it is odd to have a function called update_pkey_reg() called right
> before a write_pkru().  Can we call this update_pkey_value?  or just 'val'?
> Because write_pkru() actually updates the register.

Fair enough, update_pkey_val() works fine for me.

Patch
diff mbox series

diff --git a/arch/x86/include/asm/pkeys.h b/arch/x86/include/asm/pkeys.h
index be8b3e448f76..34cef29fed20 100644
--- a/arch/x86/include/asm/pkeys.h
+++ b/arch/x86/include/asm/pkeys.h
@@ -136,4 +136,6 @@  static inline int vma_pkey(struct vm_area_struct *vma)
 	return (vma->vm_flags & vma_pkey_mask) >> VM_PKEY_SHIFT;
 }
 
+u32 get_new_pkr(u32 old_pkr, int pkey, unsigned long init_val);
+
 #endif /*_ASM_X86_PKEYS_H */
diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c
index fc1ec2986e03..1def71dc8105 100644
--- a/arch/x86/kernel/fpu/xstate.c
+++ b/arch/x86/kernel/fpu/xstate.c
@@ -954,9 +954,7 @@  const void *get_xsave_field_ptr(int xfeature_nr)
 int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
 		unsigned long init_val)
 {
-	u32 old_pkru;
-	int pkey_shift = (pkey * PKR_BITS_PER_PKEY);
-	u32 new_pkru_bits = 0;
+	u32 old_pkru, new_pkru;
 
 	/*
 	 * This check implies XSAVE support.  OSPKE only gets
@@ -972,21 +970,12 @@  int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
 	 */
 	WARN_ON_ONCE(pkey >= arch_max_pkey());
 
-	/* Set the bits we need in PKRU:  */
-	if (init_val & PKEY_DISABLE_ACCESS)
-		new_pkru_bits |= PKR_AD_BIT;
-	if (init_val & PKEY_DISABLE_WRITE)
-		new_pkru_bits |= PKR_WD_BIT;
-
-	/* Shift the bits in to the correct place in PKRU for pkey: */
-	new_pkru_bits <<= pkey_shift;
-
 	/* Get old PKRU and mask off any old bits in place: */
 	old_pkru = read_pkru();
-	old_pkru &= ~((PKR_AD_BIT|PKR_WD_BIT) << pkey_shift);
+	new_pkru = get_new_pkr(old_pkru, pkey, init_val);
 
 	/* Write old part along with new part: */
-	write_pkru(old_pkru | new_pkru_bits);
+	write_pkru(new_pkru);
 
 	return 0;
 }
diff --git a/arch/x86/mm/pkeys.c b/arch/x86/mm/pkeys.c
index f5efb4007e74..a5c680d32930 100644
--- a/arch/x86/mm/pkeys.c
+++ b/arch/x86/mm/pkeys.c
@@ -208,3 +208,31 @@  static __init int setup_init_pkru(char *opt)
 	return 1;
 }
 __setup("init_pkru=", setup_init_pkru);
+
+/*
+ * Get a new pkey register value from the user values specified.
+ *
+ * Kernel users use the same flags as user space:
+ *     PKEY_DISABLE_ACCESS
+ *     PKEY_DISABLE_WRITE
+ */
+u32 get_new_pkr(u32 old_pkr, int pkey, unsigned long init_val)
+{
+	int pkey_shift = (pkey * PKR_BITS_PER_PKEY);
+	u32 new_pkr_bits = 0;
+
+	/* Set the bits we need in the register:  */
+	if (init_val & PKEY_DISABLE_ACCESS)
+		new_pkr_bits |= PKR_AD_BIT;
+	if (init_val & PKEY_DISABLE_WRITE)
+		new_pkr_bits |= PKR_WD_BIT;
+
+	/* Shift the bits in to the correct place: */
+	new_pkr_bits <<= pkey_shift;
+
+	/* Mask off any old bits in place: */
+	old_pkr &= ~((PKR_AD_BIT | PKR_WD_BIT) << pkey_shift);
+
+	/* Return the old part along with the new part: */
+	return old_pkr | new_pkr_bits;
+}