root/arch/arm64/lib/clear_user.S
/* 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.
 */

SYM_FUNC_START(__arch_clear_user)
        add     x2, x0, x1

#ifdef CONFIG_AS_HAS_MOPS
        .arch_extension mops
alternative_if_not ARM64_HAS_MOPS
        b       .Lno_mops
alternative_else_nop_endif

USER(9f, setpt  [x0]!, x1!, xzr)
USER(6f, setmt  [x0]!, x1!, xzr)
USER(6f, setet  [x0]!, x1!, xzr)
        mov     x0, #0
        ret
.Lno_mops:
#endif

        subs    x1, x1, #8
        b.mi    2f

1:      .p2align 4
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
6:      b.cs    9f
        // Registers are in Option A format
        add     x0, x0, x1
        b       9f
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)