linux/tools/testing/selftests/vm/pkey-powerpc.h
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0 */
   2
   3#ifndef _PKEYS_POWERPC_H
   4#define _PKEYS_POWERPC_H
   5
   6#ifndef SYS_mprotect_key
   7# define SYS_mprotect_key       386
   8#endif
   9#ifndef SYS_pkey_alloc
  10# define SYS_pkey_alloc         384
  11# define SYS_pkey_free          385
  12#endif
  13#define REG_IP_IDX              PT_NIP
  14#define REG_TRAPNO              PT_TRAP
  15#define gregs                   gp_regs
  16#define fpregs                  fp_regs
  17#define si_pkey_offset          0x20
  18
  19#undef PKEY_DISABLE_ACCESS
  20#define PKEY_DISABLE_ACCESS     0x3  /* disable read and write */
  21
  22#undef PKEY_DISABLE_WRITE
  23#define PKEY_DISABLE_WRITE      0x2
  24
  25#define NR_PKEYS                32
  26#define NR_RESERVED_PKEYS_4K    27 /* pkey-0, pkey-1, exec-only-pkey
  27                                      and 24 other keys that cannot be
  28                                      represented in the PTE */
  29#define NR_RESERVED_PKEYS_64K_3KEYS     3 /* PowerNV and KVM: pkey-0,
  30                                             pkey-1 and exec-only key */
  31#define NR_RESERVED_PKEYS_64K_4KEYS     4 /* PowerVM: pkey-0, pkey-1,
  32                                             pkey-31 and exec-only key */
  33#define PKEY_BITS_PER_PKEY      2
  34#define HPAGE_SIZE              (1UL << 24)
  35#define PAGE_SIZE               sysconf(_SC_PAGESIZE)
  36
  37static inline u32 pkey_bit_position(int pkey)
  38{
  39        return (NR_PKEYS - pkey - 1) * PKEY_BITS_PER_PKEY;
  40}
  41
  42static inline u64 __read_pkey_reg(void)
  43{
  44        u64 pkey_reg;
  45
  46        asm volatile("mfspr %0, 0xd" : "=r" (pkey_reg));
  47
  48        return pkey_reg;
  49}
  50
  51static inline void __write_pkey_reg(u64 pkey_reg)
  52{
  53        u64 amr = pkey_reg;
  54
  55        dprintf4("%s() changing %016llx to %016llx\n",
  56                         __func__, __read_pkey_reg(), pkey_reg);
  57
  58        asm volatile("isync; mtspr 0xd, %0; isync"
  59                     : : "r" ((unsigned long)(amr)) : "memory");
  60
  61        dprintf4("%s() pkey register after changing %016llx to %016llx\n",
  62                        __func__, __read_pkey_reg(), pkey_reg);
  63}
  64
  65static inline int cpu_has_pkeys(void)
  66{
  67        /* No simple way to determine this */
  68        return 1;
  69}
  70
  71static inline bool arch_is_powervm()
  72{
  73        struct stat buf;
  74
  75        if ((stat("/sys/firmware/devicetree/base/ibm,partition-name", &buf) == 0) &&
  76            (stat("/sys/firmware/devicetree/base/hmc-managed?", &buf) == 0) &&
  77            (stat("/sys/firmware/devicetree/base/chosen/qemu,graphic-width", &buf) == -1) )
  78                return true;
  79
  80        return false;
  81}
  82
  83static inline int get_arch_reserved_keys(void)
  84{
  85        if (sysconf(_SC_PAGESIZE) == 4096)
  86                return NR_RESERVED_PKEYS_4K;
  87        else
  88                if (arch_is_powervm())
  89                        return NR_RESERVED_PKEYS_64K_4KEYS;
  90                else
  91                        return NR_RESERVED_PKEYS_64K_3KEYS;
  92}
  93
  94void expect_fault_on_read_execonly_key(void *p1, int pkey)
  95{
  96        /*
  97         * powerpc does not allow userspace to change permissions of exec-only
  98         * keys since those keys are not allocated by userspace. The signal
  99         * handler wont be able to reset the permissions, which means the code
 100         * will infinitely continue to segfault here.
 101         */
 102        return;
 103}
 104
 105/* 4-byte instructions * 16384 = 64K page */
 106#define __page_o_noops() asm(".rept 16384 ; nop; .endr")
 107
 108void *malloc_pkey_with_mprotect_subpage(long size, int prot, u16 pkey)
 109{
 110        void *ptr;
 111        int ret;
 112
 113        dprintf1("doing %s(size=%ld, prot=0x%x, pkey=%d)\n", __func__,
 114                        size, prot, pkey);
 115        pkey_assert(pkey < NR_PKEYS);
 116        ptr = mmap(NULL, size, prot, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
 117        pkey_assert(ptr != (void *)-1);
 118
 119        ret = syscall(__NR_subpage_prot, ptr, size, NULL);
 120        if (ret) {
 121                perror("subpage_perm");
 122                return PTR_ERR_ENOTSUP;
 123        }
 124
 125        ret = mprotect_pkey((void *)ptr, PAGE_SIZE, prot, pkey);
 126        pkey_assert(!ret);
 127        record_pkey_malloc(ptr, size, prot);
 128
 129        dprintf1("%s() for pkey %d @ %p\n", __func__, pkey, ptr);
 130        return ptr;
 131}
 132
 133#endif /* _PKEYS_POWERPC_H */
 134