Skip to content

Commit 0c416bc

Browse files
sandip4ntorvalds
authored andcommitted
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 <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Acked-by: Dave Hansen <[email protected]> Cc: "Desnes A. Nunes do Rosario" <[email protected]> Cc: Florian Weimer <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: Ram Pai <[email protected]> Cc: Thiago Jung Bauermann <[email protected]> Cc: "Aneesh Kumar K.V" <[email protected]> Cc: Michael Ellerman <[email protected]> Cc: Michal Hocko <[email protected]> Cc: Michal Suchanek <[email protected]> Cc: Shuah Khan <[email protected]> Link: http://lkml.kernel.org/r/2ad9705f4f68ca7e72155cc583415e5a979546f1.1585646528.git.sandipan@linux.ibm.com Signed-off-by: Linus Torvalds <[email protected]>
1 parent 4dbdd94 commit 0c416bc

File tree

3 files changed

+36
-23
lines changed

3 files changed

+36
-23
lines changed

tools/testing/selftests/vm/pkey-helpers.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,28 @@ extern void abort_hooks(void);
8080
#error Architecture not supported
8181
#endif /* arch */
8282

83+
#define PKEY_MASK (PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE)
84+
85+
static inline u64 set_pkey_bits(u64 reg, int pkey, u64 flags)
86+
{
87+
u32 shift = pkey_bit_position(pkey);
88+
/* mask out bits from pkey in old value */
89+
reg &= ~((u64)PKEY_MASK << shift);
90+
/* OR in new bits for pkey */
91+
reg |= (flags & PKEY_MASK) << shift;
92+
return reg;
93+
}
94+
95+
static inline u64 get_pkey_bits(u64 reg, int pkey)
96+
{
97+
u32 shift = pkey_bit_position(pkey);
98+
/*
99+
* shift down the relevant bits to the lowest two, then
100+
* mask off all the other higher bits
101+
*/
102+
return ((reg >> shift) & PKEY_MASK);
103+
}
104+
83105
extern u64 shadow_pkey_reg;
84106

85107
static inline u64 _read_pkey_reg(int line)

tools/testing/selftests/vm/pkey-x86.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,11 @@ static inline int cpu_has_pku(void)
118118
return 1;
119119
}
120120

121+
static inline u32 pkey_bit_position(int pkey)
122+
{
123+
return pkey * PKEY_BITS_PER_PKEY;
124+
}
125+
121126
#define XSTATE_PKEY_BIT (9)
122127
#define XSTATE_PKEY 0x200
123128

tools/testing/selftests/vm/protection_keys.c

Lines changed: 9 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -334,25 +334,13 @@ pid_t fork_lazy_child(void)
334334

335335
static u32 hw_pkey_get(int pkey, unsigned long flags)
336336
{
337-
u32 mask = (PKEY_DISABLE_ACCESS|PKEY_DISABLE_WRITE);
338337
u64 pkey_reg = __read_pkey_reg();
339-
u64 shifted_pkey_reg;
340-
u32 masked_pkey_reg;
341338

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

346-
shifted_pkey_reg = (pkey_reg >> (pkey * PKEY_BITS_PER_PKEY));
347-
dprintf2("%s() shifted_pkey_reg: %016llx\n", __func__,
348-
shifted_pkey_reg);
349-
masked_pkey_reg = shifted_pkey_reg & mask;
350-
dprintf2("%s() masked pkey_reg: %x\n", __func__, masked_pkey_reg);
351-
/*
352-
* shift down the relevant bits to the lowest two, then
353-
* mask off all the other high bits.
354-
*/
355-
return masked_pkey_reg;
343+
return (u32) get_pkey_bits(pkey_reg, pkey);
356344
}
357345

358346
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)
364352
/* make sure that 'rights' only contains the bits we expect: */
365353
assert(!(rights & ~mask));
366354

367-
/* copy old pkey_reg */
368-
new_pkey_reg = old_pkey_reg;
369-
/* mask out bits from pkey in old value: */
370-
new_pkey_reg &= ~(mask << (pkey * PKEY_BITS_PER_PKEY));
371-
/* OR in new bits for pkey: */
372-
new_pkey_reg |= (rights << (pkey * PKEY_BITS_PER_PKEY));
355+
/* modify bits accordingly in old pkey_reg and assign it */
356+
new_pkey_reg = set_pkey_bits(old_pkey_reg, pkey, rights);
373357

374358
__write_pkey_reg(new_pkey_reg);
375359

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

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

439423
ret = hw_pkey_set(pkey, pkey_rights, 0);
440-
shadow_pkey_reg &= ~(flags << (pkey * 2));
424+
shadow_pkey_reg = set_pkey_bits(shadow_pkey_reg, pkey, pkey_rights);
441425
pkey_assert(ret >= 0);
442426

443427
pkey_rights = hw_pkey_get(pkey, syscall_flags);
@@ -513,7 +497,8 @@ int alloc_pkey(void)
513497
shadow_pkey_reg);
514498
if (ret) {
515499
/* clear both the bits: */
516-
shadow_pkey_reg &= ~(0x3 << (ret * 2));
500+
shadow_pkey_reg = set_pkey_bits(shadow_pkey_reg, ret,
501+
~PKEY_MASK);
517502
dprintf4("%s()::%d, ret: %d pkey_reg: 0x%016llx"
518503
" shadow: 0x%016llx\n",
519504
__func__,
@@ -523,7 +508,8 @@ int alloc_pkey(void)
523508
* move the new state in from init_val
524509
* (remember, we cheated and init_val == pkey_reg format)
525510
*/
526-
shadow_pkey_reg |= (init_val << (ret * 2));
511+
shadow_pkey_reg = set_pkey_bits(shadow_pkey_reg, ret,
512+
init_val);
527513
}
528514
dprintf4("%s()::%d, ret: %d pkey_reg: 0x%016llx"
529515
" shadow: 0x%016llx\n",

0 commit comments

Comments
 (0)