18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * arch/alpha/lib/copy_user.S
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copy to/from user space, handling exceptions as we go..  This
68c2ecf20Sopenharmony_ci * isn't exactly pretty.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * This is essentially the same as "memcpy()", but with a few twists.
98c2ecf20Sopenharmony_ci * Notably, we have to make sure that $0 is always up-to-date and
108c2ecf20Sopenharmony_ci * contains the right "bytes left to copy" value (and that it is updated
118c2ecf20Sopenharmony_ci * only _after_ a successful copy). There is also some rather minor
128c2ecf20Sopenharmony_ci * exception setup stuff..
138c2ecf20Sopenharmony_ci */
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include <asm/export.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci/* Allow an exception for an insn; exit if we get one.  */
188c2ecf20Sopenharmony_ci#define EXI(x,y...)			\
198c2ecf20Sopenharmony_ci	99: x,##y;			\
208c2ecf20Sopenharmony_ci	.section __ex_table,"a";	\
218c2ecf20Sopenharmony_ci	.long 99b - .;			\
228c2ecf20Sopenharmony_ci	lda $31, $exitin-99b($31);	\
238c2ecf20Sopenharmony_ci	.previous
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#define EXO(x,y...)			\
268c2ecf20Sopenharmony_ci	99: x,##y;			\
278c2ecf20Sopenharmony_ci	.section __ex_table,"a";	\
288c2ecf20Sopenharmony_ci	.long 99b - .;			\
298c2ecf20Sopenharmony_ci	lda $31, $exitout-99b($31);	\
308c2ecf20Sopenharmony_ci	.previous
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	.set noat
338c2ecf20Sopenharmony_ci	.align 4
348c2ecf20Sopenharmony_ci	.globl __copy_user
358c2ecf20Sopenharmony_ci	.ent __copy_user
368c2ecf20Sopenharmony_ci__copy_user:
378c2ecf20Sopenharmony_ci	.prologue 0
388c2ecf20Sopenharmony_ci	mov $18,$0
398c2ecf20Sopenharmony_ci	and $16,7,$3
408c2ecf20Sopenharmony_ci	beq $0,$35
418c2ecf20Sopenharmony_ci	beq $3,$36
428c2ecf20Sopenharmony_ci	subq $3,8,$3
438c2ecf20Sopenharmony_ci	.align 4
448c2ecf20Sopenharmony_ci$37:
458c2ecf20Sopenharmony_ci	EXI( ldq_u $1,0($17) )
468c2ecf20Sopenharmony_ci	EXO( ldq_u $2,0($16) )
478c2ecf20Sopenharmony_ci	extbl $1,$17,$1
488c2ecf20Sopenharmony_ci	mskbl $2,$16,$2
498c2ecf20Sopenharmony_ci	insbl $1,$16,$1
508c2ecf20Sopenharmony_ci	addq $3,1,$3
518c2ecf20Sopenharmony_ci	bis $1,$2,$1
528c2ecf20Sopenharmony_ci	EXO( stq_u $1,0($16) )
538c2ecf20Sopenharmony_ci	subq $0,1,$0
548c2ecf20Sopenharmony_ci	addq $16,1,$16
558c2ecf20Sopenharmony_ci	addq $17,1,$17
568c2ecf20Sopenharmony_ci	beq $0,$41
578c2ecf20Sopenharmony_ci	bne $3,$37
588c2ecf20Sopenharmony_ci$36:
598c2ecf20Sopenharmony_ci	and $17,7,$1
608c2ecf20Sopenharmony_ci	bic $0,7,$4
618c2ecf20Sopenharmony_ci	beq $1,$43
628c2ecf20Sopenharmony_ci	beq $4,$48
638c2ecf20Sopenharmony_ci	EXI( ldq_u $3,0($17) )
648c2ecf20Sopenharmony_ci	.align 4
658c2ecf20Sopenharmony_ci$50:
668c2ecf20Sopenharmony_ci	EXI( ldq_u $2,8($17) )
678c2ecf20Sopenharmony_ci	subq $4,8,$4
688c2ecf20Sopenharmony_ci	extql $3,$17,$3
698c2ecf20Sopenharmony_ci	extqh $2,$17,$1
708c2ecf20Sopenharmony_ci	bis $3,$1,$1
718c2ecf20Sopenharmony_ci	EXO( stq $1,0($16) )
728c2ecf20Sopenharmony_ci	addq $17,8,$17
738c2ecf20Sopenharmony_ci	subq $0,8,$0
748c2ecf20Sopenharmony_ci	addq $16,8,$16
758c2ecf20Sopenharmony_ci	bis $2,$2,$3
768c2ecf20Sopenharmony_ci	bne $4,$50
778c2ecf20Sopenharmony_ci$48:
788c2ecf20Sopenharmony_ci	beq $0,$41
798c2ecf20Sopenharmony_ci	.align 4
808c2ecf20Sopenharmony_ci$57:
818c2ecf20Sopenharmony_ci	EXI( ldq_u $1,0($17) )
828c2ecf20Sopenharmony_ci	EXO( ldq_u $2,0($16) )
838c2ecf20Sopenharmony_ci	extbl $1,$17,$1
848c2ecf20Sopenharmony_ci	mskbl $2,$16,$2
858c2ecf20Sopenharmony_ci	insbl $1,$16,$1
868c2ecf20Sopenharmony_ci	bis $1,$2,$1
878c2ecf20Sopenharmony_ci	EXO( stq_u $1,0($16) )
888c2ecf20Sopenharmony_ci	subq $0,1,$0
898c2ecf20Sopenharmony_ci	addq $16,1,$16
908c2ecf20Sopenharmony_ci	addq $17,1,$17
918c2ecf20Sopenharmony_ci	bne $0,$57
928c2ecf20Sopenharmony_ci	br $31,$41
938c2ecf20Sopenharmony_ci	.align 4
948c2ecf20Sopenharmony_ci$43:
958c2ecf20Sopenharmony_ci	beq $4,$65
968c2ecf20Sopenharmony_ci	.align 4
978c2ecf20Sopenharmony_ci$66:
988c2ecf20Sopenharmony_ci	EXI( ldq $1,0($17) )
998c2ecf20Sopenharmony_ci	subq $4,8,$4
1008c2ecf20Sopenharmony_ci	EXO( stq $1,0($16) )
1018c2ecf20Sopenharmony_ci	addq $17,8,$17
1028c2ecf20Sopenharmony_ci	subq $0,8,$0
1038c2ecf20Sopenharmony_ci	addq $16,8,$16
1048c2ecf20Sopenharmony_ci	bne $4,$66
1058c2ecf20Sopenharmony_ci$65:
1068c2ecf20Sopenharmony_ci	beq $0,$41
1078c2ecf20Sopenharmony_ci	EXI( ldq $2,0($17) )
1088c2ecf20Sopenharmony_ci	EXO( ldq $1,0($16) )
1098c2ecf20Sopenharmony_ci	mskql $2,$0,$2
1108c2ecf20Sopenharmony_ci	mskqh $1,$0,$1
1118c2ecf20Sopenharmony_ci	bis $2,$1,$2
1128c2ecf20Sopenharmony_ci	EXO( stq $2,0($16) )
1138c2ecf20Sopenharmony_ci	bis $31,$31,$0
1148c2ecf20Sopenharmony_ci$41:
1158c2ecf20Sopenharmony_ci$35:
1168c2ecf20Sopenharmony_ci$exitin:
1178c2ecf20Sopenharmony_ci$exitout:
1188c2ecf20Sopenharmony_ci	ret $31,($26),1
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	.end __copy_user
1218c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__copy_user)
122