162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * arch/alpha/lib/clear_user.S
462306a36Sopenharmony_ci * Contributed by Richard Henderson <rth@tamu.edu>
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Zero user space, handling exceptions as we go.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * We have to make sure that $0 is always up-to-date and contains the
962306a36Sopenharmony_ci * right "bytes left to zero" value (and that it is updated only _after_
1062306a36Sopenharmony_ci * a successful copy).  There is also some rather minor exception setup
1162306a36Sopenharmony_ci * stuff.
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci#include <linux/export.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci/* Allow an exception for an insn; exit if we get one.  */
1662306a36Sopenharmony_ci#define EX(x,y...)			\
1762306a36Sopenharmony_ci	99: x,##y;			\
1862306a36Sopenharmony_ci	.section __ex_table,"a";	\
1962306a36Sopenharmony_ci	.long 99b - .;			\
2062306a36Sopenharmony_ci	lda $31, $exception-99b($31); 	\
2162306a36Sopenharmony_ci	.previous
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci	.set noat
2462306a36Sopenharmony_ci	.set noreorder
2562306a36Sopenharmony_ci	.align 4
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	.globl __clear_user
2862306a36Sopenharmony_ci	.ent __clear_user
2962306a36Sopenharmony_ci	.frame	$30, 0, $26
3062306a36Sopenharmony_ci	.prologue 0
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci$loop:
3362306a36Sopenharmony_ci	and	$1, 3, $4	# e0    :
3462306a36Sopenharmony_ci	beq	$4, 1f		# .. e1 :
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci0:	EX( stq_u $31, 0($16) )	# e0    : zero one word
3762306a36Sopenharmony_ci	subq	$0, 8, $0	# .. e1 :
3862306a36Sopenharmony_ci	subq	$4, 1, $4	# e0    :
3962306a36Sopenharmony_ci	addq	$16, 8, $16	# .. e1 :
4062306a36Sopenharmony_ci	bne	$4, 0b		# e1    :
4162306a36Sopenharmony_ci	unop			#       :
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci1:	bic	$1, 3, $1	# e0    :
4462306a36Sopenharmony_ci	beq	$1, $tail	# .. e1 :
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci2:	EX( stq_u $31, 0($16) )	# e0    : zero four words
4762306a36Sopenharmony_ci	subq	$0, 8, $0	# .. e1 :
4862306a36Sopenharmony_ci	EX( stq_u $31, 8($16) )	# e0    :
4962306a36Sopenharmony_ci	subq	$0, 8, $0	# .. e1 :
5062306a36Sopenharmony_ci	EX( stq_u $31, 16($16) )	# e0    :
5162306a36Sopenharmony_ci	subq	$0, 8, $0	# .. e1 :
5262306a36Sopenharmony_ci	EX( stq_u $31, 24($16) )	# e0    :
5362306a36Sopenharmony_ci	subq	$0, 8, $0	# .. e1 :
5462306a36Sopenharmony_ci	subq	$1, 4, $1	# e0    :
5562306a36Sopenharmony_ci	addq	$16, 32, $16	# .. e1 :
5662306a36Sopenharmony_ci	bne	$1, 2b		# e1    :
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci$tail:
5962306a36Sopenharmony_ci	bne	$2, 1f		# e1    : is there a tail to do?
6062306a36Sopenharmony_ci	ret	$31, ($26), 1	# .. e1 :
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci1:	EX( ldq_u $5, 0($16) )	# e0    :
6362306a36Sopenharmony_ci	clr	$0		# .. e1 :
6462306a36Sopenharmony_ci	nop			# e1    :
6562306a36Sopenharmony_ci	mskqh	$5, $0, $5	# e0    :
6662306a36Sopenharmony_ci	EX( stq_u $5, 0($16) )	# e0    :
6762306a36Sopenharmony_ci	ret	$31, ($26), 1	# .. e1 :
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci__clear_user:
7062306a36Sopenharmony_ci	and	$17, $17, $0
7162306a36Sopenharmony_ci	and	$16, 7, $4	# e0    : find dest misalignment
7262306a36Sopenharmony_ci	beq	$0, $zerolength # .. e1 :
7362306a36Sopenharmony_ci	addq	$0, $4, $1	# e0    : bias counter
7462306a36Sopenharmony_ci	and	$1, 7, $2	# e1    : number of bytes in tail
7562306a36Sopenharmony_ci	srl	$1, 3, $1	# e0    :
7662306a36Sopenharmony_ci	beq	$4, $loop	# .. e1 :
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	EX( ldq_u $5, 0($16) )	# e0    : load dst word to mask back in
7962306a36Sopenharmony_ci	beq	$1, $oneword	# .. e1 : sub-word store?
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	mskql	$5, $16, $5	# e0    : take care of misaligned head
8262306a36Sopenharmony_ci	addq	$16, 8, $16	# .. e1 :
8362306a36Sopenharmony_ci	EX( stq_u $5, -8($16) )	# e0    :
8462306a36Sopenharmony_ci	addq	$0, $4, $0	# .. e1 : bytes left -= 8 - misalignment
8562306a36Sopenharmony_ci	subq	$1, 1, $1	# e0    :
8662306a36Sopenharmony_ci	subq	$0, 8, $0	# .. e1 :
8762306a36Sopenharmony_ci	br	$loop		# e1    :
8862306a36Sopenharmony_ci	unop			#       :
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci$oneword:
9162306a36Sopenharmony_ci	mskql	$5, $16, $4	# e0    :
9262306a36Sopenharmony_ci	mskqh	$5, $2, $5	# e0    :
9362306a36Sopenharmony_ci	or	$5, $4, $5	# e1    :
9462306a36Sopenharmony_ci	EX( stq_u $5, 0($16) )	# e0    :
9562306a36Sopenharmony_ci	clr	$0		# .. e1 :
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci$zerolength:
9862306a36Sopenharmony_ci$exception:
9962306a36Sopenharmony_ci	ret	$31, ($26), 1	# .. e1 :
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	.end __clear_user
10262306a36Sopenharmony_ci	EXPORT_SYMBOL(__clear_user)
103