0001
0002
0003
0004
0005
0006 #ifndef _SELFTESTS_POWERPC_PKEYS_H
0007 #define _SELFTESTS_POWERPC_PKEYS_H
0008
0009 #include <sys/mman.h>
0010
0011 #include "reg.h"
0012 #include "utils.h"
0013
0014
0015
0016
0017
0018 #undef PKEY_DISABLE_ACCESS
0019 #define PKEY_DISABLE_ACCESS 0x3
0020
0021 #undef PKEY_DISABLE_WRITE
0022 #define PKEY_DISABLE_WRITE 0x2
0023
0024 #undef PKEY_DISABLE_EXECUTE
0025 #define PKEY_DISABLE_EXECUTE 0x4
0026
0027
0028 #ifndef SEGV_PKUERR
0029 #define SEGV_PKUERR 4
0030 #endif
0031
0032 #define SI_PKEY_OFFSET 0x20
0033
0034 #define __NR_pkey_mprotect 386
0035 #define __NR_pkey_alloc 384
0036 #define __NR_pkey_free 385
0037
0038 #define PKEY_BITS_PER_PKEY 2
0039 #define NR_PKEYS 32
0040 #define PKEY_BITS_MASK ((1UL << PKEY_BITS_PER_PKEY) - 1)
0041
0042 inline unsigned long pkeyreg_get(void)
0043 {
0044 return mfspr(SPRN_AMR);
0045 }
0046
0047 inline void pkeyreg_set(unsigned long amr)
0048 {
0049 set_amr(amr);
0050 }
0051
0052 void pkey_set_rights(int pkey, unsigned long rights)
0053 {
0054 unsigned long amr, shift;
0055
0056 shift = (NR_PKEYS - pkey - 1) * PKEY_BITS_PER_PKEY;
0057 amr = pkeyreg_get();
0058 amr &= ~(PKEY_BITS_MASK << shift);
0059 amr |= (rights & PKEY_BITS_MASK) << shift;
0060 pkeyreg_set(amr);
0061 }
0062
0063 int sys_pkey_mprotect(void *addr, size_t len, int prot, int pkey)
0064 {
0065 return syscall(__NR_pkey_mprotect, addr, len, prot, pkey);
0066 }
0067
0068 int sys_pkey_alloc(unsigned long flags, unsigned long rights)
0069 {
0070 return syscall(__NR_pkey_alloc, flags, rights);
0071 }
0072
0073 int sys_pkey_free(int pkey)
0074 {
0075 return syscall(__NR_pkey_free, pkey);
0076 }
0077
0078 int pkeys_unsupported(void)
0079 {
0080 bool hash_mmu = false;
0081 int pkey;
0082
0083
0084 FAIL_IF(using_hash_mmu(&hash_mmu));
0085 SKIP_IF(!hash_mmu);
0086
0087
0088 pkey = sys_pkey_alloc(0, 0);
0089 SKIP_IF(pkey < 0);
0090 sys_pkey_free(pkey);
0091
0092 return 0;
0093 }
0094
0095 int siginfo_pkey(siginfo_t *si)
0096 {
0097
0098
0099
0100
0101 #ifdef si_pkey
0102 return si->si_pkey;
0103 #else
0104 return *((int *)(((char *) si) + SI_PKEY_OFFSET));
0105 #endif
0106 }
0107
0108 #define pkey_rights(r) ({ \
0109 static char buf[4] = "rwx"; \
0110 unsigned int amr_bits; \
0111 if ((r) & PKEY_DISABLE_EXECUTE) \
0112 buf[2] = '-'; \
0113 amr_bits = (r) & PKEY_BITS_MASK; \
0114 if (amr_bits & PKEY_DISABLE_WRITE) \
0115 buf[1] = '-'; \
0116 if (amr_bits & PKEY_DISABLE_ACCESS & ~PKEY_DISABLE_WRITE) \
0117 buf[0] = '-'; \
0118 buf; \
0119 })
0120
0121 unsigned long next_pkey_rights(unsigned long rights)
0122 {
0123 if (rights == PKEY_DISABLE_ACCESS)
0124 return PKEY_DISABLE_EXECUTE;
0125 else if (rights == (PKEY_DISABLE_ACCESS | PKEY_DISABLE_EXECUTE))
0126 return 0;
0127
0128 if ((rights & PKEY_BITS_MASK) == 0)
0129 rights |= PKEY_DISABLE_WRITE;
0130 else if ((rights & PKEY_BITS_MASK) == PKEY_DISABLE_WRITE)
0131 rights |= PKEY_DISABLE_ACCESS;
0132
0133 return rights;
0134 }
0135
0136 #endif