linux/tools/testing/selftests/vm/pkey-x86.h
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0 */
   2
   3#ifndef _PKEYS_X86_H
   4#define _PKEYS_X86_H
   5
   6#ifdef __i386__
   7
   8#ifndef SYS_mprotect_key
   9# define SYS_mprotect_key       380
  10#endif
  11
  12#ifndef SYS_pkey_alloc
  13# define SYS_pkey_alloc         381
  14# define SYS_pkey_free          382
  15#endif
  16
  17#define REG_IP_IDX              REG_EIP
  18#define si_pkey_offset          0x14
  19
  20#else
  21
  22#ifndef SYS_mprotect_key
  23# define SYS_mprotect_key       329
  24#endif
  25
  26#ifndef SYS_pkey_alloc
  27# define SYS_pkey_alloc         330
  28# define SYS_pkey_free          331
  29#endif
  30
  31#define REG_IP_IDX              REG_RIP
  32#define si_pkey_offset          0x20
  33
  34#endif
  35
  36#ifndef PKEY_DISABLE_ACCESS
  37# define PKEY_DISABLE_ACCESS    0x1
  38#endif
  39
  40#ifndef PKEY_DISABLE_WRITE
  41# define PKEY_DISABLE_WRITE     0x2
  42#endif
  43
  44#define NR_PKEYS                16
  45#define NR_RESERVED_PKEYS       2 /* pkey-0 and exec-only-pkey */
  46#define PKEY_BITS_PER_PKEY      2
  47#define HPAGE_SIZE              (1UL<<21)
  48#define PAGE_SIZE               4096
  49#define MB                      (1<<20)
  50
  51static inline void __page_o_noops(void)
  52{
  53        /* 8-bytes of instruction * 512 bytes = 1 page */
  54        asm(".rept 512 ; nopl 0x7eeeeeee(%eax) ; .endr");
  55}
  56
  57static inline u64 __read_pkey_reg(void)
  58{
  59        unsigned int eax, edx;
  60        unsigned int ecx = 0;
  61        unsigned pkey_reg;
  62
  63        asm volatile(".byte 0x0f,0x01,0xee\n\t"
  64                     : "=a" (eax), "=d" (edx)
  65                     : "c" (ecx));
  66        pkey_reg = eax;
  67        return pkey_reg;
  68}
  69
  70static inline void __write_pkey_reg(u64 pkey_reg)
  71{
  72        unsigned int eax = pkey_reg;
  73        unsigned int ecx = 0;
  74        unsigned int edx = 0;
  75
  76        dprintf4("%s() changing %016llx to %016llx\n", __func__,
  77                        __read_pkey_reg(), pkey_reg);
  78        asm volatile(".byte 0x0f,0x01,0xef\n\t"
  79                     : : "a" (eax), "c" (ecx), "d" (edx));
  80        assert(pkey_reg == __read_pkey_reg());
  81}
  82
  83static inline void __cpuid(unsigned int *eax, unsigned int *ebx,
  84                unsigned int *ecx, unsigned int *edx)
  85{
  86        /* ecx is often an input as well as an output. */
  87        asm volatile(
  88                "cpuid;"
  89                : "=a" (*eax),
  90                  "=b" (*ebx),
  91                  "=c" (*ecx),
  92                  "=d" (*edx)
  93                : "0" (*eax), "2" (*ecx));
  94}
  95
  96/* Intel-defined CPU features, CPUID level 0x00000007:0 (ecx) */
  97#define X86_FEATURE_PKU        (1<<3) /* Protection Keys for Userspace */
  98#define X86_FEATURE_OSPKE      (1<<4) /* OS Protection Keys Enable */
  99
 100static inline int cpu_has_pkeys(void)
 101{
 102        unsigned int eax;
 103        unsigned int ebx;
 104        unsigned int ecx;
 105        unsigned int edx;
 106
 107        eax = 0x7;
 108        ecx = 0x0;
 109        __cpuid(&eax, &ebx, &ecx, &edx);
 110
 111        if (!(ecx & X86_FEATURE_PKU)) {
 112                dprintf2("cpu does not have PKU\n");
 113                return 0;
 114        }
 115        if (!(ecx & X86_FEATURE_OSPKE)) {
 116                dprintf2("cpu does not have OSPKE\n");
 117                return 0;
 118        }
 119        return 1;
 120}
 121
 122static inline u32 pkey_bit_position(int pkey)
 123{
 124        return pkey * PKEY_BITS_PER_PKEY;
 125}
 126
 127#define XSTATE_PKEY_BIT (9)
 128#define XSTATE_PKEY     0x200
 129
 130int pkey_reg_xstate_offset(void)
 131{
 132        unsigned int eax;
 133        unsigned int ebx;
 134        unsigned int ecx;
 135        unsigned int edx;
 136        int xstate_offset;
 137        int xstate_size;
 138        unsigned long XSTATE_CPUID = 0xd;
 139        int leaf;
 140
 141        /* assume that XSTATE_PKEY is set in XCR0 */
 142        leaf = XSTATE_PKEY_BIT;
 143        {
 144                eax = XSTATE_CPUID;
 145                ecx = leaf;
 146                __cpuid(&eax, &ebx, &ecx, &edx);
 147
 148                if (leaf == XSTATE_PKEY_BIT) {
 149                        xstate_offset = ebx;
 150                        xstate_size = eax;
 151                }
 152        }
 153
 154        if (xstate_size == 0) {
 155                printf("could not find size/offset of PKEY in xsave state\n");
 156                return 0;
 157        }
 158
 159        return xstate_offset;
 160}
 161
 162static inline int get_arch_reserved_keys(void)
 163{
 164        return NR_RESERVED_PKEYS;
 165}
 166
 167void expect_fault_on_read_execonly_key(void *p1, int pkey)
 168{
 169        int ptr_contents;
 170
 171        ptr_contents = read_ptr(p1);
 172        dprintf2("ptr (%p) contents@%d: %x\n", p1, __LINE__, ptr_contents);
 173        expected_pkey_fault(pkey);
 174}
 175
 176void *malloc_pkey_with_mprotect_subpage(long size, int prot, u16 pkey)
 177{
 178        return PTR_ERR_ENOTSUP;
 179}
 180
 181#endif /* _PKEYS_X86_H */
 182