Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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_REG_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
44static 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
54static 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
68static inline int cpu_has_pkeys(void)
69{
70 /* No simple way to determine this */
71 return 1;
72}
73
74static inline u32 pkey_bit_position(int pkey)
75{
76 return pkey * PKEY_BITS_PER_PKEY;
77}
78
79static inline int get_arch_reserved_keys(void)
80{
81 return NR_RESERVED_PKEYS;
82}
83
84static inline void expect_fault_on_read_execonly_key(void *p1, int pkey)
85{
86}
87
88static inline 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
94static 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
114static 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
130static 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 */