diff options
Diffstat (limited to 'arch/arm64/lib/clear_user.S')
-rw-r--r-- | arch/arm64/lib/clear_user.S | 55 |
1 files changed, 55 insertions, 0 deletions
diff --git a/arch/arm64/lib/clear_user.S b/arch/arm64/lib/clear_user.S new file mode 100644 index 0000000000..a5a5f5b97b --- /dev/null +++ b/arch/arm64/lib/clear_user.S @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2021 Arm Ltd. + */ + +#include <linux/linkage.h> +#include <asm/asm-uaccess.h> + + .text + +/* Prototype: int __arch_clear_user(void *addr, size_t sz) + * Purpose : clear some user memory + * Params : addr - user memory address to clear + * : sz - number of bytes to clear + * Returns : number of bytes NOT cleared + * + * Alignment fixed up by hardware. + */ + + .p2align 4 + // Alignment is for the loop, but since the prologue (including BTI) + // is also 16 bytes we can keep any padding outside the function +SYM_FUNC_START(__arch_clear_user) + add x2, x0, x1 + subs x1, x1, #8 + b.mi 2f +1: +USER(9f, sttr xzr, [x0]) + add x0, x0, #8 + subs x1, x1, #8 + b.hi 1b +USER(9f, sttr xzr, [x2, #-8]) + mov x0, #0 + ret + +2: tbz x1, #2, 3f +USER(9f, sttr wzr, [x0]) +USER(8f, sttr wzr, [x2, #-4]) + mov x0, #0 + ret + +3: tbz x1, #1, 4f +USER(9f, sttrh wzr, [x0]) +4: tbz x1, #0, 5f +USER(7f, sttrb wzr, [x2, #-1]) +5: mov x0, #0 + ret + + // Exception fixups +7: sub x0, x2, #5 // Adjust for faulting on the final byte... +8: add x0, x0, #4 // ...or the second word of the 4-7 byte case +9: sub x0, x2, x0 + ret +SYM_FUNC_END(__arch_clear_user) +EXPORT_SYMBOL(__arch_clear_user) |