summaryrefslogtreecommitdiffstats
path: root/arch/arm64/lib/clear_user.S
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm64/lib/clear_user.S')
-rw-r--r--arch/arm64/lib/clear_user.S55
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 000000000..a5a5f5b97
--- /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)