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: Sandipan Das <sandipan@linux.ibm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Acked-by: Dave 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: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
4dbdd947cb
commit
0c416bcaef
@ -80,6 +80,28 @@ extern void abort_hooks(void);
|
|||||||
#error Architecture not supported
|
#error Architecture not supported
|
||||||
#endif /* arch */
|
#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;
|
extern u64 shadow_pkey_reg;
|
||||||
|
|
||||||
static inline u64 _read_pkey_reg(int line)
|
static inline u64 _read_pkey_reg(int line)
|
||||||
|
@ -118,6 +118,11 @@ static inline int cpu_has_pku(void)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline u32 pkey_bit_position(int pkey)
|
||||||
|
{
|
||||||
|
return pkey * PKEY_BITS_PER_PKEY;
|
||||||
|
}
|
||||||
|
|
||||||
#define XSTATE_PKEY_BIT (9)
|
#define XSTATE_PKEY_BIT (9)
|
||||||
#define XSTATE_PKEY 0x200
|
#define XSTATE_PKEY 0x200
|
||||||
|
|
||||||
|
@ -334,25 +334,13 @@ pid_t fork_lazy_child(void)
|
|||||||
|
|
||||||
static u32 hw_pkey_get(int pkey, unsigned long flags)
|
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 pkey_reg = __read_pkey_reg();
|
||||||
u64 shifted_pkey_reg;
|
|
||||||
u32 masked_pkey_reg;
|
|
||||||
|
|
||||||
dprintf1("%s(pkey=%d, flags=%lx) = %x / %d\n",
|
dprintf1("%s(pkey=%d, flags=%lx) = %x / %d\n",
|
||||||
__func__, pkey, flags, 0, 0);
|
__func__, pkey, flags, 0, 0);
|
||||||
dprintf2("%s() raw pkey_reg: %016llx\n", __func__, pkey_reg);
|
dprintf2("%s() raw pkey_reg: %016llx\n", __func__, pkey_reg);
|
||||||
|
|
||||||
shifted_pkey_reg = (pkey_reg >> (pkey * PKEY_BITS_PER_PKEY));
|
return (u32) get_pkey_bits(pkey_reg, 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hw_pkey_set(int pkey, unsigned long rights, unsigned long flags)
|
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: */
|
/* make sure that 'rights' only contains the bits we expect: */
|
||||||
assert(!(rights & ~mask));
|
assert(!(rights & ~mask));
|
||||||
|
|
||||||
/* copy old pkey_reg */
|
/* modify bits accordingly in old pkey_reg and assign it */
|
||||||
new_pkey_reg = old_pkey_reg;
|
new_pkey_reg = set_pkey_bits(old_pkey_reg, pkey, rights);
|
||||||
/* 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));
|
|
||||||
|
|
||||||
__write_pkey_reg(new_pkey_reg);
|
__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);
|
ret = hw_pkey_set(pkey, pkey_rights, syscall_flags);
|
||||||
assert(!ret);
|
assert(!ret);
|
||||||
/* pkey_reg and flags have the same format */
|
/* 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",
|
dprintf1("%s(%d) shadow: 0x%016llx\n",
|
||||||
__func__, pkey, shadow_pkey_reg);
|
__func__, pkey, shadow_pkey_reg);
|
||||||
|
|
||||||
@ -437,7 +421,7 @@ void pkey_disable_clear(int pkey, int flags)
|
|||||||
pkey_rights |= flags;
|
pkey_rights |= flags;
|
||||||
|
|
||||||
ret = hw_pkey_set(pkey, pkey_rights, 0);
|
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_assert(ret >= 0);
|
||||||
|
|
||||||
pkey_rights = hw_pkey_get(pkey, syscall_flags);
|
pkey_rights = hw_pkey_get(pkey, syscall_flags);
|
||||||
@ -513,7 +497,8 @@ int alloc_pkey(void)
|
|||||||
shadow_pkey_reg);
|
shadow_pkey_reg);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
/* clear both the bits: */
|
/* 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"
|
dprintf4("%s()::%d, ret: %d pkey_reg: 0x%016llx"
|
||||||
" shadow: 0x%016llx\n",
|
" shadow: 0x%016llx\n",
|
||||||
__func__,
|
__func__,
|
||||||
@ -523,7 +508,8 @@ int alloc_pkey(void)
|
|||||||
* move the new state in from init_val
|
* move the new state in from init_val
|
||||||
* (remember, we cheated and init_val == pkey_reg format)
|
* (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"
|
dprintf4("%s()::%d, ret: %d pkey_reg: 0x%016llx"
|
||||||
" shadow: 0x%016llx\n",
|
" shadow: 0x%016llx\n",
|
||||||
|
Loading…
Reference in New Issue
Block a user