18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2020-2021 Loongson Technology Corporation Limited
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <asm/alternative-asm.h>
78c2ecf20Sopenharmony_ci#include <asm/asm.h>
88c2ecf20Sopenharmony_ci#include <asm/asmmacro.h>
98c2ecf20Sopenharmony_ci#include <asm/asm-extable.h>
108c2ecf20Sopenharmony_ci#include <asm/cpu.h>
118c2ecf20Sopenharmony_ci#include <asm/export.h>
128c2ecf20Sopenharmony_ci#include <asm/regdef.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ciSYM_FUNC_START(__copy_user)
158c2ecf20Sopenharmony_ci	/*
168c2ecf20Sopenharmony_ci	 * Some CPUs support hardware unaligned access
178c2ecf20Sopenharmony_ci	 */
188c2ecf20Sopenharmony_ci	ALTERNATIVE	"b __copy_user_generic",	\
198c2ecf20Sopenharmony_ci			"b __copy_user_fast", CPU_FEATURE_UAL
208c2ecf20Sopenharmony_ciSYM_FUNC_END(__copy_user)
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__copy_user)
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci/*
258c2ecf20Sopenharmony_ci * unsigned long __copy_user_generic(void *to, const void *from, size_t n)
268c2ecf20Sopenharmony_ci *
278c2ecf20Sopenharmony_ci * a0: to
288c2ecf20Sopenharmony_ci * a1: from
298c2ecf20Sopenharmony_ci * a2: n
308c2ecf20Sopenharmony_ci */
318c2ecf20Sopenharmony_ciSYM_FUNC_START(__copy_user_generic)
328c2ecf20Sopenharmony_ci	beqz	a2, 3f
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci1:	ld.b	t0, a1, 0
358c2ecf20Sopenharmony_ci2:	st.b	t0, a0, 0
368c2ecf20Sopenharmony_ci	addi.d	a0, a0, 1
378c2ecf20Sopenharmony_ci	addi.d	a1, a1, 1
388c2ecf20Sopenharmony_ci	addi.d	a2, a2, -1
398c2ecf20Sopenharmony_ci	bgt	a2, zero, 1b
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci3:	move	a0, a2
428c2ecf20Sopenharmony_ci	jr	ra
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	_asm_extable 1b, 3b
458c2ecf20Sopenharmony_ci	_asm_extable 2b, 3b
468c2ecf20Sopenharmony_ciSYM_FUNC_END(__copy_user_generic)
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci/*
498c2ecf20Sopenharmony_ci * unsigned long __copy_user_fast(void *to, const void *from, unsigned long n)
508c2ecf20Sopenharmony_ci *
518c2ecf20Sopenharmony_ci * a0: to
528c2ecf20Sopenharmony_ci * a1: from
538c2ecf20Sopenharmony_ci * a2: n
548c2ecf20Sopenharmony_ci */
558c2ecf20Sopenharmony_ciSYM_FUNC_START(__copy_user_fast)
568c2ecf20Sopenharmony_ci	sltui	t0, a2, 9
578c2ecf20Sopenharmony_ci	bnez	t0, .Lsmall
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci0:	ld.d	t0, a1, 0
608c2ecf20Sopenharmony_ci1:	st.d	t0, a0, 0
618c2ecf20Sopenharmony_ci	add.d	a3, a1, a2
628c2ecf20Sopenharmony_ci	add.d	a2, a0, a2
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	/* align up destination address */
658c2ecf20Sopenharmony_ci	andi	t1, a0, 7
668c2ecf20Sopenharmony_ci	sub.d	t0, zero, t1
678c2ecf20Sopenharmony_ci	addi.d	t0, t0, 8
688c2ecf20Sopenharmony_ci	add.d	a1, a1, t0
698c2ecf20Sopenharmony_ci	add.d	a0, a0, t0
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	addi.d	a4, a3, -64
728c2ecf20Sopenharmony_ci	bgeu	a1, a4, .Llt64
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	/* copy 64 bytes at a time */
758c2ecf20Sopenharmony_ci.Lloop64:
768c2ecf20Sopenharmony_ci2:	ld.d	t0, a1, 0
778c2ecf20Sopenharmony_ci3:	ld.d	t1, a1, 8
788c2ecf20Sopenharmony_ci4:	ld.d	t2, a1, 16
798c2ecf20Sopenharmony_ci5:	ld.d	t3, a1, 24
808c2ecf20Sopenharmony_ci6:	ld.d	t4, a1, 32
818c2ecf20Sopenharmony_ci7:	ld.d	t5, a1, 40
828c2ecf20Sopenharmony_ci8:	ld.d	t6, a1, 48
838c2ecf20Sopenharmony_ci9:	ld.d	t7, a1, 56
848c2ecf20Sopenharmony_ci10:	st.d	t0, a0, 0
858c2ecf20Sopenharmony_ci11:	st.d	t1, a0, 8
868c2ecf20Sopenharmony_ci12:	st.d	t2, a0, 16
878c2ecf20Sopenharmony_ci13:	st.d	t3, a0, 24
888c2ecf20Sopenharmony_ci14:	st.d	t4, a0, 32
898c2ecf20Sopenharmony_ci15:	st.d	t5, a0, 40
908c2ecf20Sopenharmony_ci16:	st.d	t6, a0, 48
918c2ecf20Sopenharmony_ci17:	st.d	t7, a0, 56
928c2ecf20Sopenharmony_ci	addi.d	a1, a1, 64
938c2ecf20Sopenharmony_ci	addi.d	a0, a0, 64
948c2ecf20Sopenharmony_ci	bltu	a1, a4, .Lloop64
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	/* copy the remaining bytes */
978c2ecf20Sopenharmony_ci.Llt64:
988c2ecf20Sopenharmony_ci	addi.d	a4, a3, -32
998c2ecf20Sopenharmony_ci	bgeu	a1, a4, .Llt32
1008c2ecf20Sopenharmony_ci18:	ld.d	t0, a1, 0
1018c2ecf20Sopenharmony_ci19:	ld.d	t1, a1, 8
1028c2ecf20Sopenharmony_ci20:	ld.d	t2, a1, 16
1038c2ecf20Sopenharmony_ci21:	ld.d	t3, a1, 24
1048c2ecf20Sopenharmony_ci22:	st.d	t0, a0, 0
1058c2ecf20Sopenharmony_ci23:	st.d	t1, a0, 8
1068c2ecf20Sopenharmony_ci24:	st.d	t2, a0, 16
1078c2ecf20Sopenharmony_ci25:	st.d	t3, a0, 24
1088c2ecf20Sopenharmony_ci	addi.d	a1, a1, 32
1098c2ecf20Sopenharmony_ci	addi.d	a0, a0, 32
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci.Llt32:
1128c2ecf20Sopenharmony_ci	addi.d	a4, a3, -16
1138c2ecf20Sopenharmony_ci	bgeu	a1, a4, .Llt16
1148c2ecf20Sopenharmony_ci26:	ld.d	t0, a1, 0
1158c2ecf20Sopenharmony_ci27:	ld.d	t1, a1, 8
1168c2ecf20Sopenharmony_ci28:	st.d	t0, a0, 0
1178c2ecf20Sopenharmony_ci29:	st.d	t1, a0, 8
1188c2ecf20Sopenharmony_ci	addi.d	a1, a1, 16
1198c2ecf20Sopenharmony_ci	addi.d	a0, a0, 16
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci.Llt16:
1228c2ecf20Sopenharmony_ci	addi.d	a4, a3, -8
1238c2ecf20Sopenharmony_ci	bgeu	a1, a4, .Llt8
1248c2ecf20Sopenharmony_ci30:	ld.d	t0, a1, 0
1258c2ecf20Sopenharmony_ci31:	st.d	t0, a0, 0
1268c2ecf20Sopenharmony_ci	addi.d	a1, a1, 8
1278c2ecf20Sopenharmony_ci	addi.d	a0, a0, 8
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci.Llt8:
1308c2ecf20Sopenharmony_ci32:	ld.d	t0, a3, -8
1318c2ecf20Sopenharmony_ci33:	st.d	t0, a2, -8
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	/* return */
1348c2ecf20Sopenharmony_ci	move	a0, zero
1358c2ecf20Sopenharmony_ci	jr	ra
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	.align	5
1388c2ecf20Sopenharmony_ci.Lsmall:
1398c2ecf20Sopenharmony_ci	pcaddi	t0, 8
1408c2ecf20Sopenharmony_ci	slli.d	a3, a2, 5
1418c2ecf20Sopenharmony_ci	add.d	t0, t0, a3
1428c2ecf20Sopenharmony_ci	jr	t0
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	.align	5
1458c2ecf20Sopenharmony_ci	move	a0, zero
1468c2ecf20Sopenharmony_ci	jr	ra
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	.align	5
1498c2ecf20Sopenharmony_ci34:	ld.b	t0, a1, 0
1508c2ecf20Sopenharmony_ci35:	st.b	t0, a0, 0
1518c2ecf20Sopenharmony_ci	move	a0, zero
1528c2ecf20Sopenharmony_ci	jr	ra
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	.align	5
1558c2ecf20Sopenharmony_ci36:	ld.h	t0, a1, 0
1568c2ecf20Sopenharmony_ci37:	st.h	t0, a0, 0
1578c2ecf20Sopenharmony_ci	move	a0, zero
1588c2ecf20Sopenharmony_ci	jr	ra
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	.align	5
1618c2ecf20Sopenharmony_ci38:	ld.h	t0, a1, 0
1628c2ecf20Sopenharmony_ci39:	ld.b	t1, a1, 2
1638c2ecf20Sopenharmony_ci40:	st.h	t0, a0, 0
1648c2ecf20Sopenharmony_ci41:	st.b	t1, a0, 2
1658c2ecf20Sopenharmony_ci	move	a0, zero
1668c2ecf20Sopenharmony_ci	jr	ra
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	.align	5
1698c2ecf20Sopenharmony_ci42:	ld.w	t0, a1, 0
1708c2ecf20Sopenharmony_ci43:	st.w	t0, a0, 0
1718c2ecf20Sopenharmony_ci	move	a0, zero
1728c2ecf20Sopenharmony_ci	jr	ra
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	.align	5
1758c2ecf20Sopenharmony_ci44:	ld.w	t0, a1, 0
1768c2ecf20Sopenharmony_ci45:	ld.b	t1, a1, 4
1778c2ecf20Sopenharmony_ci46:	st.w	t0, a0, 0
1788c2ecf20Sopenharmony_ci47:	st.b	t1, a0, 4
1798c2ecf20Sopenharmony_ci	move	a0, zero
1808c2ecf20Sopenharmony_ci	jr	ra
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	.align	5
1838c2ecf20Sopenharmony_ci48:	ld.w	t0, a1, 0
1848c2ecf20Sopenharmony_ci49:	ld.h	t1, a1, 4
1858c2ecf20Sopenharmony_ci50:	st.w	t0, a0, 0
1868c2ecf20Sopenharmony_ci51:	st.h	t1, a0, 4
1878c2ecf20Sopenharmony_ci	move	a0, zero
1888c2ecf20Sopenharmony_ci	jr	ra
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	.align	5
1918c2ecf20Sopenharmony_ci52:	ld.w	t0, a1, 0
1928c2ecf20Sopenharmony_ci53:	ld.w	t1, a1, 3
1938c2ecf20Sopenharmony_ci54:	st.w	t0, a0, 0
1948c2ecf20Sopenharmony_ci55:	st.w	t1, a0, 3
1958c2ecf20Sopenharmony_ci	move	a0, zero
1968c2ecf20Sopenharmony_ci	jr	ra
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	.align	5
1998c2ecf20Sopenharmony_ci56:	ld.d	t0, a1, 0
2008c2ecf20Sopenharmony_ci57:	st.d	t0, a0, 0
2018c2ecf20Sopenharmony_ci	move	a0, zero
2028c2ecf20Sopenharmony_ci	jr	ra
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	/* fixup and ex_table */
2058c2ecf20Sopenharmony_ci.Llarge_fixup:
2068c2ecf20Sopenharmony_ci	sub.d	a2, a2, a0
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci.Lsmall_fixup:
2098c2ecf20Sopenharmony_ci58:	ld.b	t0, a1, 0
2108c2ecf20Sopenharmony_ci59:	st.b	t0, a0, 0
2118c2ecf20Sopenharmony_ci	addi.d	a0, a0, 1
2128c2ecf20Sopenharmony_ci	addi.d	a1, a1, 1
2138c2ecf20Sopenharmony_ci	addi.d	a2, a2, -1
2148c2ecf20Sopenharmony_ci	bgt	a2, zero, 58b
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci.Lexit:
2178c2ecf20Sopenharmony_ci	move	a0, a2
2188c2ecf20Sopenharmony_ci	jr	ra
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	_asm_extable 0b, .Lsmall_fixup
2218c2ecf20Sopenharmony_ci	_asm_extable 1b, .Lsmall_fixup
2228c2ecf20Sopenharmony_ci	_asm_extable 2b, .Llarge_fixup
2238c2ecf20Sopenharmony_ci	_asm_extable 3b, .Llarge_fixup
2248c2ecf20Sopenharmony_ci	_asm_extable 4b, .Llarge_fixup
2258c2ecf20Sopenharmony_ci	_asm_extable 5b, .Llarge_fixup
2268c2ecf20Sopenharmony_ci	_asm_extable 6b, .Llarge_fixup
2278c2ecf20Sopenharmony_ci	_asm_extable 7b, .Llarge_fixup
2288c2ecf20Sopenharmony_ci	_asm_extable 8b, .Llarge_fixup
2298c2ecf20Sopenharmony_ci	_asm_extable 9b, .Llarge_fixup
2308c2ecf20Sopenharmony_ci	_asm_extable 10b, .Llarge_fixup
2318c2ecf20Sopenharmony_ci	_asm_extable 11b, .Llarge_fixup
2328c2ecf20Sopenharmony_ci	_asm_extable 12b, .Llarge_fixup
2338c2ecf20Sopenharmony_ci	_asm_extable 13b, .Llarge_fixup
2348c2ecf20Sopenharmony_ci	_asm_extable 14b, .Llarge_fixup
2358c2ecf20Sopenharmony_ci	_asm_extable 15b, .Llarge_fixup
2368c2ecf20Sopenharmony_ci	_asm_extable 16b, .Llarge_fixup
2378c2ecf20Sopenharmony_ci	_asm_extable 17b, .Llarge_fixup
2388c2ecf20Sopenharmony_ci	_asm_extable 18b, .Llarge_fixup
2398c2ecf20Sopenharmony_ci	_asm_extable 19b, .Llarge_fixup
2408c2ecf20Sopenharmony_ci	_asm_extable 20b, .Llarge_fixup
2418c2ecf20Sopenharmony_ci	_asm_extable 21b, .Llarge_fixup
2428c2ecf20Sopenharmony_ci	_asm_extable 22b, .Llarge_fixup
2438c2ecf20Sopenharmony_ci	_asm_extable 23b, .Llarge_fixup
2448c2ecf20Sopenharmony_ci	_asm_extable 24b, .Llarge_fixup
2458c2ecf20Sopenharmony_ci	_asm_extable 25b, .Llarge_fixup
2468c2ecf20Sopenharmony_ci	_asm_extable 26b, .Llarge_fixup
2478c2ecf20Sopenharmony_ci	_asm_extable 27b, .Llarge_fixup
2488c2ecf20Sopenharmony_ci	_asm_extable 28b, .Llarge_fixup
2498c2ecf20Sopenharmony_ci	_asm_extable 29b, .Llarge_fixup
2508c2ecf20Sopenharmony_ci	_asm_extable 30b, .Llarge_fixup
2518c2ecf20Sopenharmony_ci	_asm_extable 31b, .Llarge_fixup
2528c2ecf20Sopenharmony_ci	_asm_extable 32b, .Llarge_fixup
2538c2ecf20Sopenharmony_ci	_asm_extable 33b, .Llarge_fixup
2548c2ecf20Sopenharmony_ci	_asm_extable 34b, .Lexit
2558c2ecf20Sopenharmony_ci	_asm_extable 35b, .Lexit
2568c2ecf20Sopenharmony_ci	_asm_extable 36b, .Lsmall_fixup
2578c2ecf20Sopenharmony_ci	_asm_extable 37b, .Lsmall_fixup
2588c2ecf20Sopenharmony_ci	_asm_extable 38b, .Lsmall_fixup
2598c2ecf20Sopenharmony_ci	_asm_extable 39b, .Lsmall_fixup
2608c2ecf20Sopenharmony_ci	_asm_extable 40b, .Lsmall_fixup
2618c2ecf20Sopenharmony_ci	_asm_extable 41b, .Lsmall_fixup
2628c2ecf20Sopenharmony_ci	_asm_extable 42b, .Lsmall_fixup
2638c2ecf20Sopenharmony_ci	_asm_extable 43b, .Lsmall_fixup
2648c2ecf20Sopenharmony_ci	_asm_extable 44b, .Lsmall_fixup
2658c2ecf20Sopenharmony_ci	_asm_extable 45b, .Lsmall_fixup
2668c2ecf20Sopenharmony_ci	_asm_extable 46b, .Lsmall_fixup
2678c2ecf20Sopenharmony_ci	_asm_extable 47b, .Lsmall_fixup
2688c2ecf20Sopenharmony_ci	_asm_extable 48b, .Lsmall_fixup
2698c2ecf20Sopenharmony_ci	_asm_extable 49b, .Lsmall_fixup
2708c2ecf20Sopenharmony_ci	_asm_extable 50b, .Lsmall_fixup
2718c2ecf20Sopenharmony_ci	_asm_extable 51b, .Lsmall_fixup
2728c2ecf20Sopenharmony_ci	_asm_extable 52b, .Lsmall_fixup
2738c2ecf20Sopenharmony_ci	_asm_extable 53b, .Lsmall_fixup
2748c2ecf20Sopenharmony_ci	_asm_extable 54b, .Lsmall_fixup
2758c2ecf20Sopenharmony_ci	_asm_extable 55b, .Lsmall_fixup
2768c2ecf20Sopenharmony_ci	_asm_extable 56b, .Lsmall_fixup
2778c2ecf20Sopenharmony_ci	_asm_extable 57b, .Lsmall_fixup
2788c2ecf20Sopenharmony_ci	_asm_extable 58b, .Lexit
2798c2ecf20Sopenharmony_ci	_asm_extable 59b, .Lexit
2808c2ecf20Sopenharmony_ciSYM_FUNC_END(__copy_user_fast)
281