xref: /linux/tools/testing/selftests/mm/pkey-arm64.h (revision 7f71507851fc7764b36a3221839607d3a45c2025)
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 #define PKEY_REG_ALLOW_NONE	0x0
35 
36 #define PKEY_BITS_PER_PKEY	4
37 #define PAGE_SIZE		sysconf(_SC_PAGESIZE)
38 #undef HPAGE_SIZE
39 #define HPAGE_SIZE		default_huge_page_size()
40 
41 /* 4-byte instructions * 16384 = 64K page */
42 #define __page_o_noops() asm(".rept 16384 ; nop; .endr")
43 
44 static inline u64 __read_pkey_reg(void)
45 {
46 	u64 pkey_reg = 0;
47 
48 	// POR_EL0
49 	asm volatile("mrs %0, S3_3_c10_c2_4" : "=r" (pkey_reg));
50 
51 	return pkey_reg;
52 }
53 
54 static inline void __write_pkey_reg(u64 pkey_reg)
55 {
56 	u64 por = pkey_reg;
57 
58 	dprintf4("%s() changing %016llx to %016llx\n",
59 			 __func__, __read_pkey_reg(), pkey_reg);
60 
61 	// POR_EL0
62 	asm volatile("msr S3_3_c10_c2_4, %0\nisb" :: "r" (por) :);
63 
64 	dprintf4("%s() pkey register after changing %016llx to %016llx\n",
65 			__func__, __read_pkey_reg(), pkey_reg);
66 }
67 
68 static inline int cpu_has_pkeys(void)
69 {
70 	/* No simple way to determine this */
71 	return 1;
72 }
73 
74 static inline u32 pkey_bit_position(int pkey)
75 {
76 	return pkey * PKEY_BITS_PER_PKEY;
77 }
78 
79 static inline int get_arch_reserved_keys(void)
80 {
81 	return NR_RESERVED_PKEYS;
82 }
83 
84 void expect_fault_on_read_execonly_key(void *p1, int pkey)
85 {
86 }
87 
88 void *malloc_pkey_with_mprotect_subpage(long size, int prot, u16 pkey)
89 {
90 	return PTR_ERR_ENOTSUP;
91 }
92 
93 #define set_pkey_bits	set_pkey_bits
94 static inline u64 set_pkey_bits(u64 reg, int pkey, u64 flags)
95 {
96 	u32 shift = pkey_bit_position(pkey);
97 	u64 new_val = POE_RWX;
98 
99 	/* mask out bits from pkey in old value */
100 	reg &= ~((u64)PKEY_MASK << shift);
101 
102 	if (flags & PKEY_DISABLE_ACCESS)
103 		new_val = POE_X;
104 	else if (flags & PKEY_DISABLE_WRITE)
105 		new_val = POE_RX;
106 
107 	/* OR in new bits for pkey */
108 	reg |= new_val << shift;
109 
110 	return reg;
111 }
112 
113 #define get_pkey_bits	get_pkey_bits
114 static inline u64 get_pkey_bits(u64 reg, int pkey)
115 {
116 	u32 shift = pkey_bit_position(pkey);
117 	/*
118 	 * shift down the relevant bits to the lowest four, then
119 	 * mask off all the other higher bits
120 	 */
121 	u32 perm = (reg >> shift) & PKEY_MASK;
122 
123 	if (perm == POE_X)
124 		return PKEY_DISABLE_ACCESS;
125 	if (perm == POE_RX)
126 		return PKEY_DISABLE_WRITE;
127 	return 0;
128 }
129 
130 static inline void aarch64_write_signal_pkey(ucontext_t *uctxt, u64 pkey)
131 {
132 	struct _aarch64_ctx *ctx = GET_UC_RESV_HEAD(uctxt);
133 	struct poe_context *poe_ctx =
134 		(struct poe_context *) get_header(ctx, POE_MAGIC,
135 						sizeof(uctxt->uc_mcontext), NULL);
136 	if (poe_ctx)
137 		poe_ctx->por_el0 = pkey;
138 }
139 
140 #endif /* _PKEYS_ARM64_H */
141