Skip to content

Commit 4fb158f

Browse files
Ram Paimpe
authored andcommitted
powerpc: track allocation status of all pkeys
Total 32 keys are available on power7 and above. However pkey 0,1 are reserved. So effectively we have 30 pkeys. On 4K kernels, we do not have 5 bits in the PTE to represent all the keys; we only have 3bits. Two of those keys are reserved; pkey 0 and pkey 1. So effectively we have 6 pkeys. This patch keeps track of reserved keys, allocated keys and keys that are currently free. Also it adds skeletal functions and macros, that the architecture-independent code expects to be available. Reviewed-by: Thiago Jung Bauermann <[email protected]> Signed-off-by: Ram Pai <[email protected]> Signed-off-by: Michael Ellerman <[email protected]>
1 parent 92e3da3 commit 4fb158f

File tree

5 files changed

+134
-4
lines changed

5 files changed

+134
-4
lines changed

arch/powerpc/include/asm/book3s/64/mmu.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,15 @@ typedef struct {
108108
#ifdef CONFIG_SPAPR_TCE_IOMMU
109109
struct list_head iommu_group_mem_list;
110110
#endif
111+
112+
#ifdef CONFIG_PPC_MEM_KEYS
113+
/*
114+
* Each bit represents one protection key.
115+
* bit set -> key allocated
116+
* bit unset -> key available for allocation
117+
*/
118+
u32 pkey_allocation_map;
119+
#endif
111120
} mm_context_t;
112121

113122
/*

arch/powerpc/include/asm/mmu_context.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,5 +193,9 @@ static inline bool arch_vma_access_permitted(struct vm_area_struct *vma,
193193
return true;
194194
}
195195

196+
#ifndef CONFIG_PPC_MEM_KEYS
197+
#define pkey_mm_init(mm)
198+
#endif /* CONFIG_PPC_MEM_KEYS */
199+
196200
#endif /* __KERNEL__ */
197201
#endif /* __ASM_POWERPC_MMU_CONTEXT_H */

arch/powerpc/include/asm/pkeys.h

Lines changed: 79 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,94 @@
1111
#include <linux/jump_label.h>
1212

1313
DECLARE_STATIC_KEY_TRUE(pkey_disabled);
14-
#define ARCH_VM_PKEY_FLAGS 0
14+
extern int pkeys_total; /* total pkeys as per device tree */
15+
extern u32 initial_allocation_mask; /* bits set for reserved keys */
16+
17+
/*
18+
* Define these here temporarily so we're not dependent on patching linux/mm.h.
19+
* Once it's updated we can drop these.
20+
*/
21+
#ifndef VM_PKEY_BIT0
22+
# define VM_PKEY_SHIFT VM_HIGH_ARCH_BIT_0
23+
# define VM_PKEY_BIT0 VM_HIGH_ARCH_0
24+
# define VM_PKEY_BIT1 VM_HIGH_ARCH_1
25+
# define VM_PKEY_BIT2 VM_HIGH_ARCH_2
26+
# define VM_PKEY_BIT3 VM_HIGH_ARCH_3
27+
# define VM_PKEY_BIT4 VM_HIGH_ARCH_4
28+
#endif
29+
30+
#define ARCH_VM_PKEY_FLAGS (VM_PKEY_BIT0 | VM_PKEY_BIT1 | VM_PKEY_BIT2 | \
31+
VM_PKEY_BIT3 | VM_PKEY_BIT4)
32+
33+
#define arch_max_pkey() pkeys_total
34+
35+
#define pkey_alloc_mask(pkey) (0x1 << pkey)
36+
37+
#define mm_pkey_allocation_map(mm) (mm->context.pkey_allocation_map)
38+
39+
#define __mm_pkey_allocated(mm, pkey) { \
40+
mm_pkey_allocation_map(mm) |= pkey_alloc_mask(pkey); \
41+
}
42+
43+
#define __mm_pkey_free(mm, pkey) { \
44+
mm_pkey_allocation_map(mm) &= ~pkey_alloc_mask(pkey); \
45+
}
46+
47+
#define __mm_pkey_is_allocated(mm, pkey) \
48+
(mm_pkey_allocation_map(mm) & pkey_alloc_mask(pkey))
49+
50+
#define __mm_pkey_is_reserved(pkey) (initial_allocation_mask & \
51+
pkey_alloc_mask(pkey))
1552

1653
static inline bool mm_pkey_is_allocated(struct mm_struct *mm, int pkey)
1754
{
18-
return false;
55+
/* A reserved key is never considered as 'explicitly allocated' */
56+
return ((pkey < arch_max_pkey()) &&
57+
!__mm_pkey_is_reserved(pkey) &&
58+
__mm_pkey_is_allocated(mm, pkey));
1959
}
2060

61+
/*
62+
* Returns a positive, 5-bit key on success, or -1 on failure.
63+
* Relies on the mmap_sem to protect against concurrency in mm_pkey_alloc() and
64+
* mm_pkey_free().
65+
*/
2166
static inline int mm_pkey_alloc(struct mm_struct *mm)
2267
{
23-
return -1;
68+
/*
69+
* Note: this is the one and only place we make sure that the pkey is
70+
* valid as far as the hardware is concerned. The rest of the kernel
71+
* trusts that only good, valid pkeys come out of here.
72+
*/
73+
u32 all_pkeys_mask = (u32)(~(0x0));
74+
int ret;
75+
76+
if (static_branch_likely(&pkey_disabled))
77+
return -1;
78+
79+
/*
80+
* Are we out of pkeys? We must handle this specially because ffz()
81+
* behavior is undefined if there are no zeros.
82+
*/
83+
if (mm_pkey_allocation_map(mm) == all_pkeys_mask)
84+
return -1;
85+
86+
ret = ffz((u32)mm_pkey_allocation_map(mm));
87+
__mm_pkey_allocated(mm, ret);
88+
return ret;
2489
}
2590

2691
static inline int mm_pkey_free(struct mm_struct *mm, int pkey)
2792
{
28-
return -EINVAL;
93+
if (static_branch_likely(&pkey_disabled))
94+
return -1;
95+
96+
if (!mm_pkey_is_allocated(mm, pkey))
97+
return -EINVAL;
98+
99+
__mm_pkey_free(mm, pkey);
100+
101+
return 0;
29102
}
30103

31104
/*
@@ -48,4 +121,6 @@ static inline int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
48121
{
49122
return 0;
50123
}
124+
125+
extern void pkey_mm_init(struct mm_struct *mm);
51126
#endif /*_ASM_POWERPC_KEYS_H */

arch/powerpc/mm/mmu_context_book3s64.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <linux/string.h>
1717
#include <linux/types.h>
1818
#include <linux/mm.h>
19+
#include <linux/pkeys.h>
1920
#include <linux/spinlock.h>
2021
#include <linux/idr.h>
2122
#include <linux/export.h>
@@ -118,6 +119,7 @@ static int hash__init_new_context(struct mm_struct *mm)
118119

119120
subpage_prot_init_new_context(mm);
120121

122+
pkey_mm_init(mm);
121123
return index;
122124
}
123125

arch/powerpc/mm/pkeys.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,61 @@
99

1010
DEFINE_STATIC_KEY_TRUE(pkey_disabled);
1111
bool pkey_execute_disable_supported;
12+
int pkeys_total; /* Total pkeys as per device tree */
13+
u32 initial_allocation_mask; /* Bits set for reserved keys */
1214

1315
int pkey_initialize(void)
1416
{
17+
int os_reserved, i;
18+
1519
/*
1620
* Disable the pkey system till everything is in place. A subsequent
1721
* patch will enable it.
1822
*/
1923
static_branch_enable(&pkey_disabled);
2024

25+
/* Lets assume 32 keys */
26+
pkeys_total = 32;
27+
28+
/*
29+
* Adjust the upper limit, based on the number of bits supported by
30+
* arch-neutral code.
31+
*/
32+
pkeys_total = min_t(int, pkeys_total,
33+
(ARCH_VM_PKEY_FLAGS >> VM_PKEY_SHIFT));
34+
2135
/*
2236
* Disable execute_disable support for now. A subsequent patch will
2337
* enable it.
2438
*/
2539
pkey_execute_disable_supported = false;
40+
41+
#ifdef CONFIG_PPC_4K_PAGES
42+
/*
43+
* The OS can manage only 8 pkeys due to its inability to represent them
44+
* in the Linux 4K PTE.
45+
*/
46+
os_reserved = pkeys_total - 8;
47+
#else
48+
os_reserved = 0;
49+
#endif
50+
/*
51+
* Bits are in LE format. NOTE: 1, 0 are reserved.
52+
* key 0 is the default key, which allows read/write/execute.
53+
* key 1 is recommended not to be used. PowerISA(3.0) page 1015,
54+
* programming note.
55+
*/
56+
initial_allocation_mask = ~0x0;
57+
for (i = 2; i < (pkeys_total - os_reserved); i++)
58+
initial_allocation_mask &= ~(0x1 << i);
2659
return 0;
2760
}
2861

2962
arch_initcall(pkey_initialize);
63+
64+
void pkey_mm_init(struct mm_struct *mm)
65+
{
66+
if (static_branch_likely(&pkey_disabled))
67+
return;
68+
mm_pkey_allocation_map(mm) = initial_allocation_mask;
69+
}

0 commit comments

Comments
 (0)