Commit 0c416bca authored by Sandipan Das's avatar Sandipan Das Committed by Linus Torvalds
Browse files

selftests: vm: pkeys: add helpers for pkey bits



This introduces some functions that help with setting or clearing bits of
a particular pkey.  This also adds an abstraction for getting a pkey's bit
position in the pkey register as this may vary across architectures.

Signed-off-by: default avatarSandipan Das <sandipan@linux.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Acked-by: default avatarDave Hansen <dave.hansen@intel.com>
Cc: "Desnes A. Nunes do Rosario" <desnesn@linux.vnet.ibm.com>
Cc: Florian Weimer <fweimer@redhat.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Ram Pai <linuxram@us.ibm.com>
Cc: Thiago Jung Bauermann <bauerman@linux.ibm.com>
Cc: "Aneesh Kumar K.V" <aneesh.kumar@linux.ibm.com>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Michal Suchanek <msuchanek@suse.de>
Cc: Shuah Khan <shuah@kernel.org>
Link: http://lkml.kernel.org/r/2ad9705f4f68ca7e72155cc583415e5a979546f1.1585646528.git.sandipan@linux.ibm.com


Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 4dbdd947
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -80,6 +80,28 @@ extern void abort_hooks(void);
#error Architecture not supported
#endif /* arch */

#define PKEY_MASK	(PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE)

static inline u64 set_pkey_bits(u64 reg, int pkey, u64 flags)
{
	u32 shift = pkey_bit_position(pkey);
	/* mask out bits from pkey in old value */
	reg &= ~((u64)PKEY_MASK << shift);
	/* OR in new bits for pkey */
	reg |= (flags & PKEY_MASK) << shift;
	return reg;
}

static inline u64 get_pkey_bits(u64 reg, int pkey)
{
	u32 shift = pkey_bit_position(pkey);
	/*
	 * shift down the relevant bits to the lowest two, then
	 * mask off all the other higher bits
	 */
	return ((reg >> shift) & PKEY_MASK);
}

extern u64 shadow_pkey_reg;

static inline u64 _read_pkey_reg(int line)
+5 −0
Original line number Diff line number Diff line
@@ -118,6 +118,11 @@ static inline int cpu_has_pku(void)
	return 1;
}

static inline u32 pkey_bit_position(int pkey)
{
	return pkey * PKEY_BITS_PER_PKEY;
}

#define XSTATE_PKEY_BIT	(9)
#define XSTATE_PKEY	0x200

+9 −23
Original line number Diff line number Diff line
@@ -334,25 +334,13 @@ pid_t fork_lazy_child(void)

static u32 hw_pkey_get(int pkey, unsigned long flags)
{
	u32 mask = (PKEY_DISABLE_ACCESS|PKEY_DISABLE_WRITE);
	u64 pkey_reg = __read_pkey_reg();
	u64 shifted_pkey_reg;
	u32 masked_pkey_reg;

	dprintf1("%s(pkey=%d, flags=%lx) = %x / %d\n",
			__func__, pkey, flags, 0, 0);
	dprintf2("%s() raw pkey_reg: %016llx\n", __func__, pkey_reg);

	shifted_pkey_reg = (pkey_reg >> (pkey * PKEY_BITS_PER_PKEY));
	dprintf2("%s() shifted_pkey_reg: %016llx\n", __func__,
			shifted_pkey_reg);
	masked_pkey_reg = shifted_pkey_reg & mask;
	dprintf2("%s() masked  pkey_reg: %x\n", __func__, masked_pkey_reg);
	/*
	 * shift down the relevant bits to the lowest two, then
	 * mask off all the other high bits.
	 */
	return masked_pkey_reg;
	return (u32) get_pkey_bits(pkey_reg, pkey);
}

static int hw_pkey_set(int pkey, unsigned long rights, unsigned long flags)
@@ -364,12 +352,8 @@ static int hw_pkey_set(int pkey, unsigned long rights, unsigned long flags)
	/* make sure that 'rights' only contains the bits we expect: */
	assert(!(rights & ~mask));

	/* copy old pkey_reg */
	new_pkey_reg = old_pkey_reg;
	/* mask out bits from pkey in old value: */
	new_pkey_reg &= ~(mask << (pkey * PKEY_BITS_PER_PKEY));
	/* OR in new bits for pkey: */
	new_pkey_reg |= (rights << (pkey * PKEY_BITS_PER_PKEY));
	/* modify bits accordingly in old pkey_reg and assign it */
	new_pkey_reg = set_pkey_bits(old_pkey_reg, pkey, rights);

	__write_pkey_reg(new_pkey_reg);

@@ -403,7 +387,7 @@ void pkey_disable_set(int pkey, int flags)
	ret = hw_pkey_set(pkey, pkey_rights, syscall_flags);
	assert(!ret);
	/* pkey_reg and flags have the same format */
	shadow_pkey_reg |= flags << (pkey * 2);
	shadow_pkey_reg = set_pkey_bits(shadow_pkey_reg, pkey, pkey_rights);
	dprintf1("%s(%d) shadow: 0x%016llx\n",
		__func__, pkey, shadow_pkey_reg);

@@ -437,7 +421,7 @@ void pkey_disable_clear(int pkey, int flags)
	pkey_rights |= flags;

	ret = hw_pkey_set(pkey, pkey_rights, 0);
	shadow_pkey_reg &= ~(flags << (pkey * 2));
	shadow_pkey_reg = set_pkey_bits(shadow_pkey_reg, pkey, pkey_rights);
	pkey_assert(ret >= 0);

	pkey_rights = hw_pkey_get(pkey, syscall_flags);
@@ -513,7 +497,8 @@ int alloc_pkey(void)
			shadow_pkey_reg);
	if (ret) {
		/* clear both the bits: */
		shadow_pkey_reg &= ~(0x3      << (ret * 2));
		shadow_pkey_reg = set_pkey_bits(shadow_pkey_reg, ret,
						~PKEY_MASK);
		dprintf4("%s()::%d, ret: %d pkey_reg: 0x%016llx"
				" shadow: 0x%016llx\n",
				__func__,
@@ -523,7 +508,8 @@ int alloc_pkey(void)
		 * move the new state in from init_val
		 * (remember, we cheated and init_val == pkey_reg format)
		 */
		shadow_pkey_reg |=  (init_val << (ret * 2));
		shadow_pkey_reg = set_pkey_bits(shadow_pkey_reg, ret,
						init_val);
	}
	dprintf4("%s()::%d, ret: %d pkey_reg: 0x%016llx"
			" shadow: 0x%016llx\n",