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

arm64: lib: Use MOPS for usercopy routines

Similarly to what was done with the memcpy() routines, make
copy_to_user(), copy_from_user() and clear_user() also use the Armv8.8
FEAT_MOPS instructions.

Both MOPS implementation options (A and B) are supported, including
asymmetric systems. The exception fixup code fixes up the registers
according to the option used.

In case of a fault the routines return precisely how much was not copied
(as required by the comment in include/linux/uaccess.h), as unprivileged
versions of CPY/SET are guaranteed not to have written past the
addresses reported in the GPRs.

The MOPS instructions could possibly be inlined into callers (and
patched to branch to the generic implementation if not detected;
similarly to what x86 does), but as a first step this patch just uses
them in the out-of-line routines.

Signed-off-by: Kristina Martšenko <kristina.martsenko@arm.com>
Acked-by: Robin Murphy <robin.murphy@arm.com>
Link: https://lore.kernel.org/r/20250228170006.390100-4-kristina.martsenko@arm.com
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>

authored by

Kristina Martšenko and committed by
Catalin Marinas
fe59e035 04a9f771

+55 -4
+4
arch/arm64/include/asm/asm-uaccess.h
··· 61 61 9999: x; \ 62 62 _asm_extable_uaccess 9999b, l 63 63 64 + #define USER_CPY(l, uaccess_is_write, x...) \ 65 + 9999: x; \ 66 + _asm_extable_uaccess_cpy 9999b, l, uaccess_is_write 67 + 64 68 /* 65 69 * Generate the assembly for LDTR/STTR with exception table entries. 66 70 * This is complicated as there is no post-increment or pair versions of the
+21 -4
arch/arm64/lib/clear_user.S
··· 17 17 * Alignment fixed up by hardware. 18 18 */ 19 19 20 - .p2align 4 21 - // Alignment is for the loop, but since the prologue (including BTI) 22 - // is also 16 bytes we can keep any padding outside the function 23 20 SYM_FUNC_START(__arch_clear_user) 24 21 add x2, x0, x1 22 + 23 + #ifdef CONFIG_AS_HAS_MOPS 24 + .arch_extension mops 25 + alternative_if_not ARM64_HAS_MOPS 26 + b .Lno_mops 27 + alternative_else_nop_endif 28 + 29 + USER(9f, setpt [x0]!, x1!, xzr) 30 + USER(6f, setmt [x0]!, x1!, xzr) 31 + USER(6f, setet [x0]!, x1!, xzr) 32 + mov x0, #0 33 + ret 34 + .Lno_mops: 35 + #endif 36 + 25 37 subs x1, x1, #8 26 38 b.mi 2f 27 - 1: 39 + 40 + 1: .p2align 4 28 41 USER(9f, sttr xzr, [x0]) 29 42 add x0, x0, #8 30 43 subs x1, x1, #8 ··· 60 47 ret 61 48 62 49 // Exception fixups 50 + 6: b.cs 9f 51 + // Registers are in Option A format 52 + add x0, x0, x1 53 + b 9f 63 54 7: sub x0, x2, #5 // Adjust for faulting on the final byte... 64 55 8: add x0, x0, #4 // ...or the second word of the 4-7 byte case 65 56 9: sub x0, x2, x0
+10
arch/arm64/lib/copy_from_user.S
··· 52 52 stp \reg1, \reg2, [\ptr], \val 53 53 .endm 54 54 55 + .macro cpy1 dst, src, count 56 + .arch_extension mops 57 + USER_CPY(9997f, 0, cpyfprt [\dst]!, [\src]!, \count!) 58 + USER_CPY(9996f, 0, cpyfmrt [\dst]!, [\src]!, \count!) 59 + USER_CPY(9996f, 0, cpyfert [\dst]!, [\src]!, \count!) 60 + .endm 61 + 55 62 end .req x5 56 63 srcin .req x15 57 64 SYM_FUNC_START(__arch_copy_from_user) ··· 69 62 ret 70 63 71 64 // Exception fixups 65 + 9996: b.cs 9997f 66 + // Registers are in Option A format 67 + add dst, dst, count 72 68 9997: cmp dst, dstin 73 69 b.ne 9998f 74 70 // Before being absolutely sure we couldn't copy anything, try harder
+10
arch/arm64/lib/copy_template.S
··· 40 40 D_h .req x14 41 41 42 42 mov dst, dstin 43 + 44 + #ifdef CONFIG_AS_HAS_MOPS 45 + alternative_if_not ARM64_HAS_MOPS 46 + b .Lno_mops 47 + alternative_else_nop_endif 48 + cpy1 dst, src, count 49 + b .Lexitfunc 50 + .Lno_mops: 51 + #endif 52 + 43 53 cmp count, #16 44 54 /*When memory length is less than 16, the accessed are not aligned.*/ 45 55 b.lo .Ltiny15
+10
arch/arm64/lib/copy_to_user.S
··· 51 51 user_stp 9997f, \reg1, \reg2, \ptr, \val 52 52 .endm 53 53 54 + .macro cpy1 dst, src, count 55 + .arch_extension mops 56 + USER_CPY(9997f, 1, cpyfpwt [\dst]!, [\src]!, \count!) 57 + USER_CPY(9996f, 1, cpyfmwt [\dst]!, [\src]!, \count!) 58 + USER_CPY(9996f, 1, cpyfewt [\dst]!, [\src]!, \count!) 59 + .endm 60 + 54 61 end .req x5 55 62 srcin .req x15 56 63 SYM_FUNC_START(__arch_copy_to_user) ··· 68 61 ret 69 62 70 63 // Exception fixups 64 + 9996: b.cs 9997f 65 + // Registers are in Option A format 66 + add dst, dst, count 71 67 9997: cmp dst, dstin 72 68 b.ne 9998f 73 69 // Before being absolutely sure we couldn't copy anything, try harder