162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * arch/alpha/lib/copy_user.S
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copy to/from user space, handling exceptions as we go..  This
662306a36Sopenharmony_ci * isn't exactly pretty.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * This is essentially the same as "memcpy()", but with a few twists.
962306a36Sopenharmony_ci * Notably, we have to make sure that $0 is always up-to-date and
1062306a36Sopenharmony_ci * contains the right "bytes left to copy" value (and that it is updated
1162306a36Sopenharmony_ci * only _after_ a successful copy). There is also some rather minor
1262306a36Sopenharmony_ci * exception setup stuff..
1362306a36Sopenharmony_ci */
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <linux/export.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci/* Allow an exception for an insn; exit if we get one.  */
1862306a36Sopenharmony_ci#define EXI(x,y...)			\
1962306a36Sopenharmony_ci	99: x,##y;			\
2062306a36Sopenharmony_ci	.section __ex_table,"a";	\
2162306a36Sopenharmony_ci	.long 99b - .;			\
2262306a36Sopenharmony_ci	lda $31, $exitin-99b($31);	\
2362306a36Sopenharmony_ci	.previous
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#define EXO(x,y...)			\
2662306a36Sopenharmony_ci	99: x,##y;			\
2762306a36Sopenharmony_ci	.section __ex_table,"a";	\
2862306a36Sopenharmony_ci	.long 99b - .;			\
2962306a36Sopenharmony_ci	lda $31, $exitout-99b($31);	\
3062306a36Sopenharmony_ci	.previous
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	.set noat
3362306a36Sopenharmony_ci	.align 4
3462306a36Sopenharmony_ci	.globl __copy_user
3562306a36Sopenharmony_ci	.ent __copy_user
3662306a36Sopenharmony_ci__copy_user:
3762306a36Sopenharmony_ci	.prologue 0
3862306a36Sopenharmony_ci	mov $18,$0
3962306a36Sopenharmony_ci	and $16,7,$3
4062306a36Sopenharmony_ci	beq $0,$35
4162306a36Sopenharmony_ci	beq $3,$36
4262306a36Sopenharmony_ci	subq $3,8,$3
4362306a36Sopenharmony_ci	.align 4
4462306a36Sopenharmony_ci$37:
4562306a36Sopenharmony_ci	EXI( ldq_u $1,0($17) )
4662306a36Sopenharmony_ci	EXO( ldq_u $2,0($16) )
4762306a36Sopenharmony_ci	extbl $1,$17,$1
4862306a36Sopenharmony_ci	mskbl $2,$16,$2
4962306a36Sopenharmony_ci	insbl $1,$16,$1
5062306a36Sopenharmony_ci	addq $3,1,$3
5162306a36Sopenharmony_ci	bis $1,$2,$1
5262306a36Sopenharmony_ci	EXO( stq_u $1,0($16) )
5362306a36Sopenharmony_ci	subq $0,1,$0
5462306a36Sopenharmony_ci	addq $16,1,$16
5562306a36Sopenharmony_ci	addq $17,1,$17
5662306a36Sopenharmony_ci	beq $0,$41
5762306a36Sopenharmony_ci	bne $3,$37
5862306a36Sopenharmony_ci$36:
5962306a36Sopenharmony_ci	and $17,7,$1
6062306a36Sopenharmony_ci	bic $0,7,$4
6162306a36Sopenharmony_ci	beq $1,$43
6262306a36Sopenharmony_ci	beq $4,$48
6362306a36Sopenharmony_ci	EXI( ldq_u $3,0($17) )
6462306a36Sopenharmony_ci	.align 4
6562306a36Sopenharmony_ci$50:
6662306a36Sopenharmony_ci	EXI( ldq_u $2,8($17) )
6762306a36Sopenharmony_ci	subq $4,8,$4
6862306a36Sopenharmony_ci	extql $3,$17,$3
6962306a36Sopenharmony_ci	extqh $2,$17,$1
7062306a36Sopenharmony_ci	bis $3,$1,$1
7162306a36Sopenharmony_ci	EXO( stq $1,0($16) )
7262306a36Sopenharmony_ci	addq $17,8,$17
7362306a36Sopenharmony_ci	subq $0,8,$0
7462306a36Sopenharmony_ci	addq $16,8,$16
7562306a36Sopenharmony_ci	bis $2,$2,$3
7662306a36Sopenharmony_ci	bne $4,$50
7762306a36Sopenharmony_ci$48:
7862306a36Sopenharmony_ci	beq $0,$41
7962306a36Sopenharmony_ci	.align 4
8062306a36Sopenharmony_ci$57:
8162306a36Sopenharmony_ci	EXI( ldq_u $1,0($17) )
8262306a36Sopenharmony_ci	EXO( ldq_u $2,0($16) )
8362306a36Sopenharmony_ci	extbl $1,$17,$1
8462306a36Sopenharmony_ci	mskbl $2,$16,$2
8562306a36Sopenharmony_ci	insbl $1,$16,$1
8662306a36Sopenharmony_ci	bis $1,$2,$1
8762306a36Sopenharmony_ci	EXO( stq_u $1,0($16) )
8862306a36Sopenharmony_ci	subq $0,1,$0
8962306a36Sopenharmony_ci	addq $16,1,$16
9062306a36Sopenharmony_ci	addq $17,1,$17
9162306a36Sopenharmony_ci	bne $0,$57
9262306a36Sopenharmony_ci	br $31,$41
9362306a36Sopenharmony_ci	.align 4
9462306a36Sopenharmony_ci$43:
9562306a36Sopenharmony_ci	beq $4,$65
9662306a36Sopenharmony_ci	.align 4
9762306a36Sopenharmony_ci$66:
9862306a36Sopenharmony_ci	EXI( ldq $1,0($17) )
9962306a36Sopenharmony_ci	subq $4,8,$4
10062306a36Sopenharmony_ci	EXO( stq $1,0($16) )
10162306a36Sopenharmony_ci	addq $17,8,$17
10262306a36Sopenharmony_ci	subq $0,8,$0
10362306a36Sopenharmony_ci	addq $16,8,$16
10462306a36Sopenharmony_ci	bne $4,$66
10562306a36Sopenharmony_ci$65:
10662306a36Sopenharmony_ci	beq $0,$41
10762306a36Sopenharmony_ci	EXI( ldq $2,0($17) )
10862306a36Sopenharmony_ci	EXO( ldq $1,0($16) )
10962306a36Sopenharmony_ci	mskql $2,$0,$2
11062306a36Sopenharmony_ci	mskqh $1,$0,$1
11162306a36Sopenharmony_ci	bis $2,$1,$2
11262306a36Sopenharmony_ci	EXO( stq $2,0($16) )
11362306a36Sopenharmony_ci	bis $31,$31,$0
11462306a36Sopenharmony_ci$41:
11562306a36Sopenharmony_ci$35:
11662306a36Sopenharmony_ci$exitin:
11762306a36Sopenharmony_ci$exitout:
11862306a36Sopenharmony_ci	ret $31,($26),1
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	.end __copy_user
12162306a36Sopenharmony_ciEXPORT_SYMBOL(__copy_user)
122