Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

arm64/sysreg: Improve PIR/POR helpers

We currently have one helper to set a PIRx_ELx's permission field to
a given value, PIRx_ELx_PERM(), and another helper to extract a
permission field from POR_ELx, POR_ELx_IDX(). The naming is pretty
confusing - it isn't clear at all that "_PERM" corresponds to a
setter and "_IDX" to a getter.

This patch aims at improving the situation by using the same
suffixes as FIELD_PREP()/FIELD_GET(), which we have already adopted
for SYS_FIELD_{PREP,GET}():

* PIRx_ELx_PERM_PREP(), POR_ELx_PERM_PREP() create a register value
where the permission field for a given index is set to a given value.

* POR_ELx_PERM_GET() extracts the permission field from a given
register value for a given index.

These helpers are not implemented using FIELD_PREP()/FIELD_GET()
because the mask may not be constant, and they need to be usable in
assembly. They are all defined in asm/sysreg.h, as one would expect
for basic sysreg-related helpers.

Finally the new POR_ELx_PERM_* macros are used for existing
calculations in signal.c and mmu.c.

Signed-off-by: Kevin Brodsky <kevin.brodsky@arm.com>
Link: https://lore.kernel.org/r/20250219164029.2309119-2-kevin.brodsky@arm.com
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>

authored by

Kevin Brodsky and committed by
Catalin Marinas
f91a3a60 0ad2507d

+34 -29
+18 -18
arch/arm64/include/asm/pgtable-prot.h
··· 169 169 #define PAGE_GCS_RO __pgprot(_PAGE_GCS_RO) 170 170 171 171 #define PIE_E0 ( \ 172 - PIRx_ELx_PERM(pte_pi_index(_PAGE_GCS), PIE_GCS) | \ 173 - PIRx_ELx_PERM(pte_pi_index(_PAGE_GCS_RO), PIE_R) | \ 174 - PIRx_ELx_PERM(pte_pi_index(_PAGE_EXECONLY), PIE_X_O) | \ 175 - PIRx_ELx_PERM(pte_pi_index(_PAGE_READONLY_EXEC), PIE_RX_O) | \ 176 - PIRx_ELx_PERM(pte_pi_index(_PAGE_SHARED_EXEC), PIE_RWX_O) | \ 177 - PIRx_ELx_PERM(pte_pi_index(_PAGE_READONLY), PIE_R_O) | \ 178 - PIRx_ELx_PERM(pte_pi_index(_PAGE_SHARED), PIE_RW_O)) 172 + PIRx_ELx_PERM_PREP(pte_pi_index(_PAGE_GCS), PIE_GCS) | \ 173 + PIRx_ELx_PERM_PREP(pte_pi_index(_PAGE_GCS_RO), PIE_R) | \ 174 + PIRx_ELx_PERM_PREP(pte_pi_index(_PAGE_EXECONLY), PIE_X_O) | \ 175 + PIRx_ELx_PERM_PREP(pte_pi_index(_PAGE_READONLY_EXEC), PIE_RX_O) | \ 176 + PIRx_ELx_PERM_PREP(pte_pi_index(_PAGE_SHARED_EXEC), PIE_RWX_O) | \ 177 + PIRx_ELx_PERM_PREP(pte_pi_index(_PAGE_READONLY), PIE_R_O) | \ 178 + PIRx_ELx_PERM_PREP(pte_pi_index(_PAGE_SHARED), PIE_RW_O)) 179 179 180 180 #define PIE_E1 ( \ 181 - PIRx_ELx_PERM(pte_pi_index(_PAGE_GCS), PIE_NONE_O) | \ 182 - PIRx_ELx_PERM(pte_pi_index(_PAGE_GCS_RO), PIE_NONE_O) | \ 183 - PIRx_ELx_PERM(pte_pi_index(_PAGE_EXECONLY), PIE_NONE_O) | \ 184 - PIRx_ELx_PERM(pte_pi_index(_PAGE_READONLY_EXEC), PIE_R) | \ 185 - PIRx_ELx_PERM(pte_pi_index(_PAGE_SHARED_EXEC), PIE_RW) | \ 186 - PIRx_ELx_PERM(pte_pi_index(_PAGE_READONLY), PIE_R) | \ 187 - PIRx_ELx_PERM(pte_pi_index(_PAGE_SHARED), PIE_RW) | \ 188 - PIRx_ELx_PERM(pte_pi_index(_PAGE_KERNEL_ROX), PIE_RX) | \ 189 - PIRx_ELx_PERM(pte_pi_index(_PAGE_KERNEL_EXEC), PIE_RWX) | \ 190 - PIRx_ELx_PERM(pte_pi_index(_PAGE_KERNEL_RO), PIE_R) | \ 191 - PIRx_ELx_PERM(pte_pi_index(_PAGE_KERNEL), PIE_RW)) 181 + PIRx_ELx_PERM_PREP(pte_pi_index(_PAGE_GCS), PIE_NONE_O) | \ 182 + PIRx_ELx_PERM_PREP(pte_pi_index(_PAGE_GCS_RO), PIE_NONE_O) | \ 183 + PIRx_ELx_PERM_PREP(pte_pi_index(_PAGE_EXECONLY), PIE_NONE_O) | \ 184 + PIRx_ELx_PERM_PREP(pte_pi_index(_PAGE_READONLY_EXEC), PIE_R) | \ 185 + PIRx_ELx_PERM_PREP(pte_pi_index(_PAGE_SHARED_EXEC), PIE_RW) | \ 186 + PIRx_ELx_PERM_PREP(pte_pi_index(_PAGE_READONLY), PIE_R) | \ 187 + PIRx_ELx_PERM_PREP(pte_pi_index(_PAGE_SHARED), PIE_RW) | \ 188 + PIRx_ELx_PERM_PREP(pte_pi_index(_PAGE_KERNEL_ROX), PIE_RX) | \ 189 + PIRx_ELx_PERM_PREP(pte_pi_index(_PAGE_KERNEL_EXEC), PIE_RWX) | \ 190 + PIRx_ELx_PERM_PREP(pte_pi_index(_PAGE_KERNEL_RO), PIE_R) | \ 191 + PIRx_ELx_PERM_PREP(pte_pi_index(_PAGE_KERNEL), PIE_RW)) 192 192 193 193 #endif /* __ASM_PGTABLE_PROT_H */
+4 -5
arch/arm64/include/asm/por.h
··· 6 6 #ifndef _ASM_ARM64_POR_H 7 7 #define _ASM_ARM64_POR_H 8 8 9 - #define POR_BITS_PER_PKEY 4 10 - #define POR_ELx_IDX(por_elx, idx) (((por_elx) >> ((idx) * POR_BITS_PER_PKEY)) & 0xf) 9 + #include <asm/sysreg.h> 11 10 12 11 static inline bool por_elx_allows_read(u64 por, u8 pkey) 13 12 { 14 - u8 perm = POR_ELx_IDX(por, pkey); 13 + u8 perm = POR_ELx_PERM_GET(pkey, por); 15 14 16 15 return perm & POE_R; 17 16 } 18 17 19 18 static inline bool por_elx_allows_write(u64 por, u8 pkey) 20 19 { 21 - u8 perm = POR_ELx_IDX(por, pkey); 20 + u8 perm = POR_ELx_PERM_GET(pkey, por); 22 21 23 22 return perm & POE_W; 24 23 } 25 24 26 25 static inline bool por_elx_allows_exec(u64 por, u8 pkey) 27 26 { 28 - u8 perm = POR_ELx_IDX(por, pkey); 27 + u8 perm = POR_ELx_PERM_GET(pkey, por); 29 28 30 29 return perm & POE_X; 31 30 }
+9 -1
arch/arm64/include/asm/sysreg.h
··· 1062 1062 #define PIE_RX UL(0xa) 1063 1063 #define PIE_RW UL(0xc) 1064 1064 #define PIE_RWX UL(0xe) 1065 + #define PIE_MASK UL(0xf) 1065 1066 1066 - #define PIRx_ELx_PERM(idx, perm) ((perm) << ((idx) * 4)) 1067 + #define PIRx_ELx_BITS_PER_IDX 4 1068 + #define PIRx_ELx_PERM_SHIFT(idx) ((idx) * PIRx_ELx_BITS_PER_IDX) 1069 + #define PIRx_ELx_PERM_PREP(idx, perm) (((perm) & PIE_MASK) << PIRx_ELx_PERM_SHIFT(idx)) 1067 1070 1068 1071 /* 1069 1072 * Permission Overlay Extension (POE) permission encodings. ··· 1080 1077 #define POE_XW UL(0x6) 1081 1078 #define POE_RXW UL(0x7) 1082 1079 #define POE_MASK UL(0xf) 1080 + 1081 + #define POR_ELx_BITS_PER_IDX 4 1082 + #define POR_ELx_PERM_SHIFT(idx) ((idx) * POR_ELx_BITS_PER_IDX) 1083 + #define POR_ELx_PERM_GET(idx, reg) (((reg) >> POR_ELx_PERM_SHIFT(idx)) & POE_MASK) 1084 + #define POR_ELx_PERM_PREP(idx, perm) (((perm) & POE_MASK) << POR_ELx_PERM_SHIFT(idx)) 1083 1085 1084 1086 /* Initial value for Permission Overlay Extension for EL0 */ 1085 1087 #define POR_EL0_INIT POE_RXW
+1 -1
arch/arm64/kernel/signal.c
··· 91 91 u64 por_enable_all = 0; 92 92 93 93 for (int pkey = 0; pkey < arch_max_pkey(); pkey++) 94 - por_enable_all |= POE_RXW << (pkey * POR_BITS_PER_PKEY); 94 + por_enable_all |= POR_ELx_PERM_PREP(pkey, POE_RXW); 95 95 96 96 ua_state->por_el0 = read_sysreg_s(SYS_POR_EL0); 97 97 write_sysreg_s(por_enable_all, SYS_POR_EL0);
+2 -4
arch/arm64/mm/mmu.c
··· 1557 1557 { 1558 1558 u64 new_por = POE_RXW; 1559 1559 u64 old_por; 1560 - u64 pkey_shift; 1561 1560 1562 1561 if (!system_supports_poe()) 1563 1562 return -ENOSPC; ··· 1581 1582 new_por &= ~POE_X; 1582 1583 1583 1584 /* Shift the bits in to the correct place in POR for pkey: */ 1584 - pkey_shift = pkey * POR_BITS_PER_PKEY; 1585 - new_por <<= pkey_shift; 1585 + new_por = POR_ELx_PERM_PREP(pkey, new_por); 1586 1586 1587 1587 /* Get old POR and mask off any old bits in place: */ 1588 1588 old_por = read_sysreg_s(SYS_POR_EL0); 1589 - old_por &= ~(POE_MASK << pkey_shift); 1589 + old_por &= ~(POE_MASK << POR_ELx_PERM_SHIFT(pkey)); 1590 1590 1591 1591 /* Write old part along with new part: */ 1592 1592 write_sysreg_s(old_por | new_por, SYS_POR_EL0);