selftests/powerpc: Move pkey helpers to headers

This moves all the pkey-related helpers to a new header
file and also a helper to print error messages in signal
handlers to the existing utils header file.

Signed-off-by: Sandipan Das <sandipan@linux.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/28e633fa9ec1a6500c12188e09ea1887b10a10c1.1595821792.git.sandipan@linux.ibm.com
This commit is contained in:
Sandipan Das 2020-07-27 09:30:35 +05:30 committed by Michael Ellerman
parent 107c55005f
commit 128d3d0210
3 changed files with 114 additions and 98 deletions

View File

@ -0,0 +1,108 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright 2020, Sandipan Das, IBM Corp.
*/
#ifndef _SELFTESTS_POWERPC_PKEYS_H
#define _SELFTESTS_POWERPC_PKEYS_H
#include <sys/mman.h>
#include "reg.h"
#include "utils.h"
/*
* Older versions of libc use the Intel-specific access rights.
* Hence, override the definitions as they might be incorrect.
*/
#undef PKEY_DISABLE_ACCESS
#define PKEY_DISABLE_ACCESS 0x3
#undef PKEY_DISABLE_WRITE
#define PKEY_DISABLE_WRITE 0x2
#undef PKEY_DISABLE_EXECUTE
#define PKEY_DISABLE_EXECUTE 0x4
/* Older versions of libc do not not define this */
#ifndef SEGV_PKUERR
#define SEGV_PKUERR 4
#endif
#define SI_PKEY_OFFSET 0x20
#define SYS_pkey_mprotect 386
#define SYS_pkey_alloc 384
#define SYS_pkey_free 385
#define PKEY_BITS_PER_PKEY 2
#define NR_PKEYS 32
#define PKEY_BITS_MASK ((1UL << PKEY_BITS_PER_PKEY) - 1)
inline unsigned long pkeyreg_get(void)
{
return mfspr(SPRN_AMR);
}
inline void pkeyreg_set(unsigned long amr)
{
set_amr(amr);
}
void pkey_set_rights(int pkey, unsigned long rights)
{
unsigned long amr, shift;
shift = (NR_PKEYS - pkey - 1) * PKEY_BITS_PER_PKEY;
amr = pkeyreg_get();
amr &= ~(PKEY_BITS_MASK << shift);
amr |= (rights & PKEY_BITS_MASK) << shift;
pkeyreg_set(amr);
}
int sys_pkey_mprotect(void *addr, size_t len, int prot, int pkey)
{
return syscall(SYS_pkey_mprotect, addr, len, prot, pkey);
}
int sys_pkey_alloc(unsigned long flags, unsigned long rights)
{
return syscall(SYS_pkey_alloc, flags, rights);
}
int sys_pkey_free(int pkey)
{
return syscall(SYS_pkey_free, pkey);
}
int pkeys_unsupported(void)
{
bool hash_mmu = false;
int pkey;
/* Protection keys are currently supported on Hash MMU only */
FAIL_IF(using_hash_mmu(&hash_mmu));
SKIP_IF(!hash_mmu);
/* Check if the system call is supported */
pkey = sys_pkey_alloc(0, 0);
SKIP_IF(pkey < 0);
sys_pkey_free(pkey);
return 0;
}
int siginfo_pkey(siginfo_t *si)
{
/*
* In older versions of libc, siginfo_t does not have si_pkey as
* a member.
*/
#ifdef si_pkey
return si->si_pkey;
#else
return *((int *)(((char *) si) + SI_PKEY_OFFSET));
#endif
}
#endif /* _SELFTESTS_POWERPC_PKEYS_H */

View File

@ -97,6 +97,10 @@ do { \
#define _str(s) #s
#define str(s) _str(s)
#define sigsafe_err(msg) ({ \
ssize_t nbytes __attribute__((unused)); \
nbytes = write(STDERR_FILENO, msg, strlen(msg)); })
/* POWER9 feature */
#ifndef PPC_FEATURE2_ARCH_3_00
#define PPC_FEATURE2_ARCH_3_00 0x00800000

View File

@ -14,83 +14,13 @@
#include <signal.h>
#include <unistd.h>
#include <sys/mman.h>
#include "reg.h"
#include "utils.h"
/*
* Older versions of libc use the Intel-specific access rights.
* Hence, override the definitions as they might be incorrect.
*/
#undef PKEY_DISABLE_ACCESS
#define PKEY_DISABLE_ACCESS 0x3
#undef PKEY_DISABLE_WRITE
#define PKEY_DISABLE_WRITE 0x2
#undef PKEY_DISABLE_EXECUTE
#define PKEY_DISABLE_EXECUTE 0x4
/* Older versions of libc do not not define this */
#ifndef SEGV_PKUERR
#define SEGV_PKUERR 4
#endif
#define SI_PKEY_OFFSET 0x20
#define SYS_pkey_mprotect 386
#define SYS_pkey_alloc 384
#define SYS_pkey_free 385
#define PKEY_BITS_PER_PKEY 2
#define NR_PKEYS 32
#define PKEY_BITS_MASK ((1UL << PKEY_BITS_PER_PKEY) - 1)
#include "pkeys.h"
#define PPC_INST_NOP 0x60000000
#define PPC_INST_TRAP 0x7fe00008
#define PPC_INST_BLR 0x4e800020
#define sigsafe_err(msg) ({ \
ssize_t nbytes __attribute__((unused)); \
nbytes = write(STDERR_FILENO, msg, strlen(msg)); })
static inline unsigned long pkeyreg_get(void)
{
return mfspr(SPRN_AMR);
}
static inline void pkeyreg_set(unsigned long amr)
{
set_amr(amr);
}
static void pkey_set_rights(int pkey, unsigned long rights)
{
unsigned long amr, shift;
shift = (NR_PKEYS - pkey - 1) * PKEY_BITS_PER_PKEY;
amr = pkeyreg_get();
amr &= ~(PKEY_BITS_MASK << shift);
amr |= (rights & PKEY_BITS_MASK) << shift;
pkeyreg_set(amr);
}
static int sys_pkey_mprotect(void *addr, size_t len, int prot, int pkey)
{
return syscall(SYS_pkey_mprotect, addr, len, prot, pkey);
}
static int sys_pkey_alloc(unsigned long flags, unsigned long rights)
{
return syscall(SYS_pkey_alloc, flags, rights);
}
static int sys_pkey_free(int pkey)
{
return syscall(SYS_pkey_free, pkey);
}
static volatile sig_atomic_t fault_pkey, fault_code, fault_type;
static volatile sig_atomic_t remaining_faults;
static volatile unsigned int *fault_addr;
@ -110,16 +40,7 @@ static void segv_handler(int signum, siginfo_t *sinfo, void *ctx)
{
int signal_pkey;
/*
* In older versions of libc, siginfo_t does not have si_pkey as
* a member.
*/
#ifdef si_pkey
signal_pkey = sinfo->si_pkey;
#else
signal_pkey = *((int *)(((char *) sinfo) + SI_PKEY_OFFSET));
#endif
signal_pkey = siginfo_pkey(sinfo);
fault_code = sinfo->si_code;
/* Check if this fault originated from the expected address */
@ -178,23 +99,6 @@ static void segv_handler(int signum, siginfo_t *sinfo, void *ctx)
remaining_faults--;
}
static int pkeys_unsupported(void)
{
bool hash_mmu = false;
int pkey;
/* Protection keys are currently supported on Hash MMU only */
FAIL_IF(using_hash_mmu(&hash_mmu));
SKIP_IF(!hash_mmu);
/* Check if the system call is supported */
pkey = sys_pkey_alloc(0, 0);
SKIP_IF(pkey < 0);
sys_pkey_free(pkey);
return 0;
}
static int test(void)
{
struct sigaction segv_act, trap_act;