162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/export.h>
762306a36Sopenharmony_ci#include <asm/alternative-asm.h>
862306a36Sopenharmony_ci#include <asm/asm.h>
962306a36Sopenharmony_ci#include <asm/asmmacro.h>
1062306a36Sopenharmony_ci#include <asm/asm-extable.h>
1162306a36Sopenharmony_ci#include <asm/cpu.h>
1262306a36Sopenharmony_ci#include <asm/regdef.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ciSYM_FUNC_START(__copy_user)
1562306a36Sopenharmony_ci	/*
1662306a36Sopenharmony_ci	 * Some CPUs support hardware unaligned access
1762306a36Sopenharmony_ci	 */
1862306a36Sopenharmony_ci	ALTERNATIVE	"b __copy_user_generic",	\
1962306a36Sopenharmony_ci			"b __copy_user_fast", CPU_FEATURE_UAL
2062306a36Sopenharmony_ciSYM_FUNC_END(__copy_user)
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ciEXPORT_SYMBOL(__copy_user)
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci/*
2562306a36Sopenharmony_ci * unsigned long __copy_user_generic(void *to, const void *from, size_t n)
2662306a36Sopenharmony_ci *
2762306a36Sopenharmony_ci * a0: to
2862306a36Sopenharmony_ci * a1: from
2962306a36Sopenharmony_ci * a2: n
3062306a36Sopenharmony_ci */
3162306a36Sopenharmony_ciSYM_FUNC_START(__copy_user_generic)
3262306a36Sopenharmony_ci	beqz	a2, 3f
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci1:	ld.b	t0, a1, 0
3562306a36Sopenharmony_ci2:	st.b	t0, a0, 0
3662306a36Sopenharmony_ci	addi.d	a0, a0, 1
3762306a36Sopenharmony_ci	addi.d	a1, a1, 1
3862306a36Sopenharmony_ci	addi.d	a2, a2, -1
3962306a36Sopenharmony_ci	bgtz	a2, 1b
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci3:	move	a0, a2
4262306a36Sopenharmony_ci	jr	ra
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	_asm_extable 1b, 3b
4562306a36Sopenharmony_ci	_asm_extable 2b, 3b
4662306a36Sopenharmony_ciSYM_FUNC_END(__copy_user_generic)
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci/*
4962306a36Sopenharmony_ci * unsigned long __copy_user_fast(void *to, const void *from, unsigned long n)
5062306a36Sopenharmony_ci *
5162306a36Sopenharmony_ci * a0: to
5262306a36Sopenharmony_ci * a1: from
5362306a36Sopenharmony_ci * a2: n
5462306a36Sopenharmony_ci */
5562306a36Sopenharmony_ciSYM_FUNC_START(__copy_user_fast)
5662306a36Sopenharmony_ci	sltui	t0, a2, 9
5762306a36Sopenharmony_ci	bnez	t0, .Lsmall
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci0:	ld.d	t0, a1, 0
6062306a36Sopenharmony_ci1:	st.d	t0, a0, 0
6162306a36Sopenharmony_ci	add.d	a3, a1, a2
6262306a36Sopenharmony_ci	add.d	a2, a0, a2
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	/* align up destination address */
6562306a36Sopenharmony_ci	andi	t1, a0, 7
6662306a36Sopenharmony_ci	sub.d	t0, zero, t1
6762306a36Sopenharmony_ci	addi.d	t0, t0, 8
6862306a36Sopenharmony_ci	add.d	a1, a1, t0
6962306a36Sopenharmony_ci	add.d	a0, a0, t0
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	addi.d	a4, a3, -64
7262306a36Sopenharmony_ci	bgeu	a1, a4, .Llt64
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	/* copy 64 bytes at a time */
7562306a36Sopenharmony_ci.Lloop64:
7662306a36Sopenharmony_ci2:	ld.d	t0, a1, 0
7762306a36Sopenharmony_ci3:	ld.d	t1, a1, 8
7862306a36Sopenharmony_ci4:	ld.d	t2, a1, 16
7962306a36Sopenharmony_ci5:	ld.d	t3, a1, 24
8062306a36Sopenharmony_ci6:	ld.d	t4, a1, 32
8162306a36Sopenharmony_ci7:	ld.d	t5, a1, 40
8262306a36Sopenharmony_ci8:	ld.d	t6, a1, 48
8362306a36Sopenharmony_ci9:	ld.d	t7, a1, 56
8462306a36Sopenharmony_ci10:	st.d	t0, a0, 0
8562306a36Sopenharmony_ci11:	st.d	t1, a0, 8
8662306a36Sopenharmony_ci12:	st.d	t2, a0, 16
8762306a36Sopenharmony_ci13:	st.d	t3, a0, 24
8862306a36Sopenharmony_ci14:	st.d	t4, a0, 32
8962306a36Sopenharmony_ci15:	st.d	t5, a0, 40
9062306a36Sopenharmony_ci16:	st.d	t6, a0, 48
9162306a36Sopenharmony_ci17:	st.d	t7, a0, 56
9262306a36Sopenharmony_ci	addi.d	a1, a1, 64
9362306a36Sopenharmony_ci	addi.d	a0, a0, 64
9462306a36Sopenharmony_ci	bltu	a1, a4, .Lloop64
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	/* copy the remaining bytes */
9762306a36Sopenharmony_ci.Llt64:
9862306a36Sopenharmony_ci	addi.d	a4, a3, -32
9962306a36Sopenharmony_ci	bgeu	a1, a4, .Llt32
10062306a36Sopenharmony_ci18:	ld.d	t0, a1, 0
10162306a36Sopenharmony_ci19:	ld.d	t1, a1, 8
10262306a36Sopenharmony_ci20:	ld.d	t2, a1, 16
10362306a36Sopenharmony_ci21:	ld.d	t3, a1, 24
10462306a36Sopenharmony_ci22:	st.d	t0, a0, 0
10562306a36Sopenharmony_ci23:	st.d	t1, a0, 8
10662306a36Sopenharmony_ci24:	st.d	t2, a0, 16
10762306a36Sopenharmony_ci25:	st.d	t3, a0, 24
10862306a36Sopenharmony_ci	addi.d	a1, a1, 32
10962306a36Sopenharmony_ci	addi.d	a0, a0, 32
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci.Llt32:
11262306a36Sopenharmony_ci	addi.d	a4, a3, -16
11362306a36Sopenharmony_ci	bgeu	a1, a4, .Llt16
11462306a36Sopenharmony_ci26:	ld.d	t0, a1, 0
11562306a36Sopenharmony_ci27:	ld.d	t1, a1, 8
11662306a36Sopenharmony_ci28:	st.d	t0, a0, 0
11762306a36Sopenharmony_ci29:	st.d	t1, a0, 8
11862306a36Sopenharmony_ci	addi.d	a1, a1, 16
11962306a36Sopenharmony_ci	addi.d	a0, a0, 16
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci.Llt16:
12262306a36Sopenharmony_ci	addi.d	a4, a3, -8
12362306a36Sopenharmony_ci	bgeu	a1, a4, .Llt8
12462306a36Sopenharmony_ci30:	ld.d	t0, a1, 0
12562306a36Sopenharmony_ci31:	st.d	t0, a0, 0
12662306a36Sopenharmony_ci	addi.d	a1, a1, 8
12762306a36Sopenharmony_ci	addi.d	a0, a0, 8
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci.Llt8:
13062306a36Sopenharmony_ci32:	ld.d	t0, a3, -8
13162306a36Sopenharmony_ci33:	st.d	t0, a2, -8
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	/* return */
13462306a36Sopenharmony_ci	move	a0, zero
13562306a36Sopenharmony_ci	jr	ra
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	.align	5
13862306a36Sopenharmony_ci.Lsmall:
13962306a36Sopenharmony_ci	pcaddi	t0, 8
14062306a36Sopenharmony_ci	slli.d	a3, a2, 5
14162306a36Sopenharmony_ci	add.d	t0, t0, a3
14262306a36Sopenharmony_ci	jr	t0
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	.align	5
14562306a36Sopenharmony_ci	move	a0, zero
14662306a36Sopenharmony_ci	jr	ra
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	.align	5
14962306a36Sopenharmony_ci34:	ld.b	t0, a1, 0
15062306a36Sopenharmony_ci35:	st.b	t0, a0, 0
15162306a36Sopenharmony_ci	move	a0, zero
15262306a36Sopenharmony_ci	jr	ra
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	.align	5
15562306a36Sopenharmony_ci36:	ld.h	t0, a1, 0
15662306a36Sopenharmony_ci37:	st.h	t0, a0, 0
15762306a36Sopenharmony_ci	move	a0, zero
15862306a36Sopenharmony_ci	jr	ra
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	.align	5
16162306a36Sopenharmony_ci38:	ld.h	t0, a1, 0
16262306a36Sopenharmony_ci39:	ld.b	t1, a1, 2
16362306a36Sopenharmony_ci40:	st.h	t0, a0, 0
16462306a36Sopenharmony_ci41:	st.b	t1, a0, 2
16562306a36Sopenharmony_ci	move	a0, zero
16662306a36Sopenharmony_ci	jr	ra
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	.align	5
16962306a36Sopenharmony_ci42:	ld.w	t0, a1, 0
17062306a36Sopenharmony_ci43:	st.w	t0, a0, 0
17162306a36Sopenharmony_ci	move	a0, zero
17262306a36Sopenharmony_ci	jr	ra
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	.align	5
17562306a36Sopenharmony_ci44:	ld.w	t0, a1, 0
17662306a36Sopenharmony_ci45:	ld.b	t1, a1, 4
17762306a36Sopenharmony_ci46:	st.w	t0, a0, 0
17862306a36Sopenharmony_ci47:	st.b	t1, a0, 4
17962306a36Sopenharmony_ci	move	a0, zero
18062306a36Sopenharmony_ci	jr	ra
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	.align	5
18362306a36Sopenharmony_ci48:	ld.w	t0, a1, 0
18462306a36Sopenharmony_ci49:	ld.h	t1, a1, 4
18562306a36Sopenharmony_ci50:	st.w	t0, a0, 0
18662306a36Sopenharmony_ci51:	st.h	t1, a0, 4
18762306a36Sopenharmony_ci	move	a0, zero
18862306a36Sopenharmony_ci	jr	ra
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	.align	5
19162306a36Sopenharmony_ci52:	ld.w	t0, a1, 0
19262306a36Sopenharmony_ci53:	ld.w	t1, a1, 3
19362306a36Sopenharmony_ci54:	st.w	t0, a0, 0
19462306a36Sopenharmony_ci55:	st.w	t1, a0, 3
19562306a36Sopenharmony_ci	move	a0, zero
19662306a36Sopenharmony_ci	jr	ra
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	.align	5
19962306a36Sopenharmony_ci56:	ld.d	t0, a1, 0
20062306a36Sopenharmony_ci57:	st.d	t0, a0, 0
20162306a36Sopenharmony_ci	move	a0, zero
20262306a36Sopenharmony_ci	jr	ra
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	/* fixup and ex_table */
20562306a36Sopenharmony_ci.Llarge_fixup:
20662306a36Sopenharmony_ci	sub.d	a2, a2, a0
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci.Lsmall_fixup:
20962306a36Sopenharmony_ci58:	ld.b	t0, a1, 0
21062306a36Sopenharmony_ci59:	st.b	t0, a0, 0
21162306a36Sopenharmony_ci	addi.d	a0, a0, 1
21262306a36Sopenharmony_ci	addi.d	a1, a1, 1
21362306a36Sopenharmony_ci	addi.d	a2, a2, -1
21462306a36Sopenharmony_ci	bgt	a2, zero, 58b
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci.Lexit:
21762306a36Sopenharmony_ci	move	a0, a2
21862306a36Sopenharmony_ci	jr	ra
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	_asm_extable 0b, .Lsmall_fixup
22162306a36Sopenharmony_ci	_asm_extable 1b, .Lsmall_fixup
22262306a36Sopenharmony_ci	_asm_extable 2b, .Llarge_fixup
22362306a36Sopenharmony_ci	_asm_extable 3b, .Llarge_fixup
22462306a36Sopenharmony_ci	_asm_extable 4b, .Llarge_fixup
22562306a36Sopenharmony_ci	_asm_extable 5b, .Llarge_fixup
22662306a36Sopenharmony_ci	_asm_extable 6b, .Llarge_fixup
22762306a36Sopenharmony_ci	_asm_extable 7b, .Llarge_fixup
22862306a36Sopenharmony_ci	_asm_extable 8b, .Llarge_fixup
22962306a36Sopenharmony_ci	_asm_extable 9b, .Llarge_fixup
23062306a36Sopenharmony_ci	_asm_extable 10b, .Llarge_fixup
23162306a36Sopenharmony_ci	_asm_extable 11b, .Llarge_fixup
23262306a36Sopenharmony_ci	_asm_extable 12b, .Llarge_fixup
23362306a36Sopenharmony_ci	_asm_extable 13b, .Llarge_fixup
23462306a36Sopenharmony_ci	_asm_extable 14b, .Llarge_fixup
23562306a36Sopenharmony_ci	_asm_extable 15b, .Llarge_fixup
23662306a36Sopenharmony_ci	_asm_extable 16b, .Llarge_fixup
23762306a36Sopenharmony_ci	_asm_extable 17b, .Llarge_fixup
23862306a36Sopenharmony_ci	_asm_extable 18b, .Llarge_fixup
23962306a36Sopenharmony_ci	_asm_extable 19b, .Llarge_fixup
24062306a36Sopenharmony_ci	_asm_extable 20b, .Llarge_fixup
24162306a36Sopenharmony_ci	_asm_extable 21b, .Llarge_fixup
24262306a36Sopenharmony_ci	_asm_extable 22b, .Llarge_fixup
24362306a36Sopenharmony_ci	_asm_extable 23b, .Llarge_fixup
24462306a36Sopenharmony_ci	_asm_extable 24b, .Llarge_fixup
24562306a36Sopenharmony_ci	_asm_extable 25b, .Llarge_fixup
24662306a36Sopenharmony_ci	_asm_extable 26b, .Llarge_fixup
24762306a36Sopenharmony_ci	_asm_extable 27b, .Llarge_fixup
24862306a36Sopenharmony_ci	_asm_extable 28b, .Llarge_fixup
24962306a36Sopenharmony_ci	_asm_extable 29b, .Llarge_fixup
25062306a36Sopenharmony_ci	_asm_extable 30b, .Llarge_fixup
25162306a36Sopenharmony_ci	_asm_extable 31b, .Llarge_fixup
25262306a36Sopenharmony_ci	_asm_extable 32b, .Llarge_fixup
25362306a36Sopenharmony_ci	_asm_extable 33b, .Llarge_fixup
25462306a36Sopenharmony_ci	_asm_extable 34b, .Lexit
25562306a36Sopenharmony_ci	_asm_extable 35b, .Lexit
25662306a36Sopenharmony_ci	_asm_extable 36b, .Lsmall_fixup
25762306a36Sopenharmony_ci	_asm_extable 37b, .Lsmall_fixup
25862306a36Sopenharmony_ci	_asm_extable 38b, .Lsmall_fixup
25962306a36Sopenharmony_ci	_asm_extable 39b, .Lsmall_fixup
26062306a36Sopenharmony_ci	_asm_extable 40b, .Lsmall_fixup
26162306a36Sopenharmony_ci	_asm_extable 41b, .Lsmall_fixup
26262306a36Sopenharmony_ci	_asm_extable 42b, .Lsmall_fixup
26362306a36Sopenharmony_ci	_asm_extable 43b, .Lsmall_fixup
26462306a36Sopenharmony_ci	_asm_extable 44b, .Lsmall_fixup
26562306a36Sopenharmony_ci	_asm_extable 45b, .Lsmall_fixup
26662306a36Sopenharmony_ci	_asm_extable 46b, .Lsmall_fixup
26762306a36Sopenharmony_ci	_asm_extable 47b, .Lsmall_fixup
26862306a36Sopenharmony_ci	_asm_extable 48b, .Lsmall_fixup
26962306a36Sopenharmony_ci	_asm_extable 49b, .Lsmall_fixup
27062306a36Sopenharmony_ci	_asm_extable 50b, .Lsmall_fixup
27162306a36Sopenharmony_ci	_asm_extable 51b, .Lsmall_fixup
27262306a36Sopenharmony_ci	_asm_extable 52b, .Lsmall_fixup
27362306a36Sopenharmony_ci	_asm_extable 53b, .Lsmall_fixup
27462306a36Sopenharmony_ci	_asm_extable 54b, .Lsmall_fixup
27562306a36Sopenharmony_ci	_asm_extable 55b, .Lsmall_fixup
27662306a36Sopenharmony_ci	_asm_extable 56b, .Lsmall_fixup
27762306a36Sopenharmony_ci	_asm_extable 57b, .Lsmall_fixup
27862306a36Sopenharmony_ci	_asm_extable 58b, .Lexit
27962306a36Sopenharmony_ci	_asm_extable 59b, .Lexit
28062306a36Sopenharmony_ciSYM_FUNC_END(__copy_user_fast)
281