Commit | Line | Data |
---|---|---|
589944b5 RP |
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 | ||
e9506394 RP |
19 | #undef PKEY_DISABLE_ACCESS |
20 | #define PKEY_DISABLE_ACCESS 0x3 /* disable read and write */ | |
589944b5 | 21 | |
e9506394 RP |
22 | #undef PKEY_DISABLE_WRITE |
23 | #define PKEY_DISABLE_WRITE 0x2 | |
589944b5 RP |
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 */ | |
c63e5e7f DNR |
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 */ | |
589944b5 RP |
33 | #define PKEY_BITS_PER_PKEY 2 |
34 | #define HPAGE_SIZE (1UL << 24) | |
473c3cc8 | 35 | #define PAGE_SIZE sysconf(_SC_PAGESIZE) |
589944b5 RP |
36 | |
37 | static inline u32 pkey_bit_position(int pkey) | |
38 | { | |
39 | return (NR_PKEYS - pkey - 1) * PKEY_BITS_PER_PKEY; | |
40 | } | |
41 | ||
42 | static 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 | ||
51 | static 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 | ||
94c8a223 | 65 | static inline int cpu_has_pkeys(void) |
589944b5 | 66 | { |
94c8a223 | 67 | /* No simple way to determine this */ |
589944b5 RP |
68 | return 1; |
69 | } | |
70 | ||
c63e5e7f DNR |
71 | static 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 | ||
589944b5 RP |
83 | static inline int get_arch_reserved_keys(void) |
84 | { | |
85 | if (sysconf(_SC_PAGESIZE) == 4096) | |
86 | return NR_RESERVED_PKEYS_4K; | |
87 | else | |
c63e5e7f DNR |
88 | if (arch_is_powervm()) |
89 | return NR_RESERVED_PKEYS_64K_4KEYS; | |
90 | else | |
91 | return NR_RESERVED_PKEYS_64K_3KEYS; | |
589944b5 RP |
92 | } |
93 | ||
94 | void 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 | ||
6e2c2d0f RP |
108 | void *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 | ||
589944b5 | 133 | #endif /* _PKEYS_POWERPC_H */ |