1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3 * Copyright (C) 2023 Arm Ltd.
4 */
5
6 #ifndef _PKEYS_ARM64_H
7 #define _PKEYS_ARM64_H
8
9 #include "vm_util.h"
10 /* for signal frame parsing */
11 #include "../arm64/signal/testcases/testcases.h"
12
13 #ifndef SYS_mprotect_key
14 # define SYS_mprotect_key 288
15 #endif
16 #ifndef SYS_pkey_alloc
17 # define SYS_pkey_alloc 289
18 # define SYS_pkey_free 290
19 #endif
20 #define MCONTEXT_IP(mc) mc.pc
21 #define MCONTEXT_TRAPNO(mc) -1
22
23 #define PKEY_MASK 0xf
24
25 #define POE_NONE 0x0
26 #define POE_X 0x2
27 #define POE_RX 0x3
28 #define POE_RWX 0x7
29
30 #define NR_PKEYS 8
31 #define NR_RESERVED_PKEYS 1 /* pkey-0 */
32
33 #define PKEY_ALLOW_ALL 0x77777777
34
35 #define PKEY_BITS_PER_PKEY 4
36 #define PAGE_SIZE sysconf(_SC_PAGESIZE)
37 #undef HPAGE_SIZE
38 #define HPAGE_SIZE default_huge_page_size()
39
40 /* 4-byte instructions * 16384 = 64K page */
41 #define __page_o_noops() asm(".rept 16384 ; nop; .endr")
42
__read_pkey_reg(void)43 static inline u64 __read_pkey_reg(void)
44 {
45 u64 pkey_reg = 0;
46
47 // POR_EL0
48 asm volatile("mrs %0, S3_3_c10_c2_4" : "=r" (pkey_reg));
49
50 return pkey_reg;
51 }
52
__write_pkey_reg(u64 pkey_reg)53 static inline void __write_pkey_reg(u64 pkey_reg)
54 {
55 u64 por = pkey_reg;
56
57 dprintf4("%s() changing %016llx to %016llx\n",
58 __func__, __read_pkey_reg(), pkey_reg);
59
60 // POR_EL0
61 asm volatile("msr S3_3_c10_c2_4, %0\nisb" :: "r" (por) :);
62
63 dprintf4("%s() pkey register after changing %016llx to %016llx\n",
64 __func__, __read_pkey_reg(), pkey_reg);
65 }
66
cpu_has_pkeys(void)67 static inline int cpu_has_pkeys(void)
68 {
69 /* No simple way to determine this */
70 return 1;
71 }
72
pkey_bit_position(int pkey)73 static inline u32 pkey_bit_position(int pkey)
74 {
75 return pkey * PKEY_BITS_PER_PKEY;
76 }
77
get_arch_reserved_keys(void)78 static inline int get_arch_reserved_keys(void)
79 {
80 return NR_RESERVED_PKEYS;
81 }
82
expect_fault_on_read_execonly_key(void * p1,int pkey)83 void expect_fault_on_read_execonly_key(void *p1, int pkey)
84 {
85 }
86
malloc_pkey_with_mprotect_subpage(long size,int prot,u16 pkey)87 void *malloc_pkey_with_mprotect_subpage(long size, int prot, u16 pkey)
88 {
89 return PTR_ERR_ENOTSUP;
90 }
91
92 #define set_pkey_bits set_pkey_bits
set_pkey_bits(u64 reg,int pkey,u64 flags)93 static inline u64 set_pkey_bits(u64 reg, int pkey, u64 flags)
94 {
95 u32 shift = pkey_bit_position(pkey);
96 u64 new_val = POE_RWX;
97
98 /* mask out bits from pkey in old value */
99 reg &= ~((u64)PKEY_MASK << shift);
100
101 if (flags & PKEY_DISABLE_ACCESS)
102 new_val = POE_X;
103 else if (flags & PKEY_DISABLE_WRITE)
104 new_val = POE_RX;
105
106 /* OR in new bits for pkey */
107 reg |= new_val << shift;
108
109 return reg;
110 }
111
112 #define get_pkey_bits get_pkey_bits
get_pkey_bits(u64 reg,int pkey)113 static inline u64 get_pkey_bits(u64 reg, int pkey)
114 {
115 u32 shift = pkey_bit_position(pkey);
116 /*
117 * shift down the relevant bits to the lowest four, then
118 * mask off all the other higher bits
119 */
120 u32 perm = (reg >> shift) & PKEY_MASK;
121
122 if (perm == POE_X)
123 return PKEY_DISABLE_ACCESS;
124 if (perm == POE_RX)
125 return PKEY_DISABLE_WRITE;
126 return 0;
127 }
128
aarch64_write_signal_pkey(ucontext_t * uctxt,u64 pkey)129 static void aarch64_write_signal_pkey(ucontext_t *uctxt, u64 pkey)
130 {
131 struct _aarch64_ctx *ctx = GET_UC_RESV_HEAD(uctxt);
132 struct poe_context *poe_ctx =
133 (struct poe_context *) get_header(ctx, POE_MAGIC,
134 sizeof(uctxt->uc_mcontext), NULL);
135 if (poe_ctx)
136 poe_ctx->por_el0 = pkey;
137 }
138
139 #endif /* _PKEYS_ARM64_H */
140