1 /* SPDX-License-Identifier: GPL-2.0 */ 2 /* 3 * Copyright (C) 2023 Arm Ltd. 4 * 5 * Based on arch/x86/include/asm/pkeys.h 6 */ 7 8 #ifndef _ASM_ARM64_PKEYS_H 9 #define _ASM_ARM64_PKEYS_H 10 11 #define ARCH_VM_PKEY_FLAGS (VM_PKEY_BIT0 | VM_PKEY_BIT1 | VM_PKEY_BIT2) 12 13 #define arch_max_pkey() 8 14 15 int arch_set_user_pkey_access(struct task_struct *tsk, int pkey, 16 unsigned long init_val); 17 18 static inline bool arch_pkeys_enabled(void) 19 { 20 return system_supports_poe(); 21 } 22 23 static inline int vma_pkey(struct vm_area_struct *vma) 24 { 25 return (vma->vm_flags & ARCH_VM_PKEY_FLAGS) >> VM_PKEY_SHIFT; 26 } 27 28 static inline int arch_override_mprotect_pkey(struct vm_area_struct *vma, 29 int prot, int pkey) 30 { 31 if (pkey != -1) 32 return pkey; 33 34 return vma_pkey(vma); 35 } 36 37 static inline int execute_only_pkey(struct mm_struct *mm) 38 { 39 // Execute-only mappings are handled by EPAN/FEAT_PAN3. 40 return -1; 41 } 42 43 #define mm_pkey_allocation_map(mm) (mm)->context.pkey_allocation_map 44 #define mm_set_pkey_allocated(mm, pkey) do { \ 45 mm_pkey_allocation_map(mm) |= (1U << pkey); \ 46 } while (0) 47 #define mm_set_pkey_free(mm, pkey) do { \ 48 mm_pkey_allocation_map(mm) &= ~(1U << pkey); \ 49 } while (0) 50 51 static inline bool mm_pkey_is_allocated(struct mm_struct *mm, int pkey) 52 { 53 /* 54 * "Allocated" pkeys are those that have been returned 55 * from pkey_alloc() or pkey 0 which is allocated 56 * implicitly when the mm is created. 57 */ 58 if (pkey < 0 || pkey >= arch_max_pkey()) 59 return false; 60 61 return mm_pkey_allocation_map(mm) & (1U << pkey); 62 } 63 64 /* 65 * Returns a positive, 3-bit key on success, or -1 on failure. 66 */ 67 static inline int mm_pkey_alloc(struct mm_struct *mm) 68 { 69 /* 70 * Note: this is the one and only place we make sure 71 * that the pkey is valid as far as the hardware is 72 * concerned. The rest of the kernel trusts that 73 * only good, valid pkeys come out of here. 74 */ 75 u8 all_pkeys_mask = GENMASK(arch_max_pkey() - 1, 0); 76 int ret; 77 78 if (!arch_pkeys_enabled()) 79 return -1; 80 81 /* 82 * Are we out of pkeys? We must handle this specially 83 * because ffz() behavior is undefined if there are no 84 * zeros. 85 */ 86 if (mm_pkey_allocation_map(mm) == all_pkeys_mask) 87 return -1; 88 89 ret = ffz(mm_pkey_allocation_map(mm)); 90 91 mm_set_pkey_allocated(mm, ret); 92 93 return ret; 94 } 95 96 static inline int mm_pkey_free(struct mm_struct *mm, int pkey) 97 { 98 if (!mm_pkey_is_allocated(mm, pkey)) 99 return -EINVAL; 100 101 mm_set_pkey_free(mm, pkey); 102 103 return 0; 104 } 105 106 #endif /* _ASM_ARM64_PKEYS_H */ 107