1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3  * Copyright (C) 2020-2021 Loongson Technology Corporation Limited
4  */
5 
6 #include <asm/alternative-asm.h>
7 #include <asm/asm.h>
8 #include <asm/asmmacro.h>
9 #include <asm/cpu.h>
10 #include <asm/export.h>
11 #include <asm/regdef.h>
12 
13 SYM_FUNC_START_WEAK(memcpy)
14 SYM_FUNC_START_ALIAS(__memcpy)
15 	/*
16 	 * Some CPUs support hardware unaligned access
17 	 */
18 	ALTERNATIVE	"b __memcpy_generic", \
19 			"b __memcpy_fast", CPU_FEATURE_UAL
20 SYM_FUNC_END(memcpy)
21 SYM_FUNC_END_ALIAS(__memcpy)
22 
23 EXPORT_SYMBOL(memcpy)
24 EXPORT_SYMBOL(__memcpy)
25 
26 /*
27  * void *__memcpy_generic(void *dst, const void *src, size_t n)
28  *
29  * a0: dst
30  * a1: src
31  * a2: n
32  */
33 SYM_FUNC_START(__memcpy_generic)
34 	move	a3, a0
35 	beqz	a2, 2f
36 
37 1:	ld.b	t0, a1, 0
38 	st.b	t0, a0, 0
39 	addi.d	a0, a0, 1
40 	addi.d	a1, a1, 1
41 	addi.d	a2, a2, -1
42 	bgt	a2, zero, 1b
43 
44 2:	move	a0, a3
45 	jr	ra
46 SYM_FUNC_END(__memcpy_generic)
47 
48 	.align	5
49 SYM_FUNC_START_NOALIGN(__memcpy_small)
50 	pcaddi	t0, 8
51 	slli.d	a2, a2, 5
52 	add.d	t0, t0, a2
53 	jr	t0
54 
55 	.align	5
56 0:	jr	ra
57 
58 	.align	5
59 1:	ld.b	t0, a1, 0
60 	st.b	t0, a0, 0
61 	jr	ra
62 
63 	.align	5
64 2:	ld.h	t0, a1, 0
65 	st.h	t0, a0, 0
66 	jr	ra
67 
68 	.align	5
69 3:	ld.h	t0, a1, 0
70 	ld.b	t1, a1, 2
71 	st.h	t0, a0, 0
72 	st.b	t1, a0, 2
73 	jr	ra
74 
75 	.align	5
76 4:	ld.w	t0, a1, 0
77 	st.w	t0, a0, 0
78 	jr	ra
79 
80 	.align	5
81 5:	ld.w	t0, a1, 0
82 	ld.b	t1, a1, 4
83 	st.w	t0, a0, 0
84 	st.b	t1, a0, 4
85 	jr	ra
86 
87 	.align	5
88 6:	ld.w	t0, a1, 0
89 	ld.h	t1, a1, 4
90 	st.w	t0, a0, 0
91 	st.h	t1, a0, 4
92 	jr	ra
93 
94 	.align	5
95 7:	ld.w	t0, a1, 0
96 	ld.w	t1, a1, 3
97 	st.w	t0, a0, 0
98 	st.w	t1, a0, 3
99 	jr	ra
100 
101 	.align	5
102 8:	ld.d	t0, a1, 0
103 	st.d	t0, a0, 0
104 	jr	ra
105 SYM_FUNC_END(__memcpy_small)
106 
107 /*
108  * void *__memcpy_fast(void *dst, const void *src, size_t n)
109  *
110  * a0: dst
111  * a1: src
112  * a2: n
113  */
114 SYM_FUNC_START(__memcpy_fast)
115 	sltui	t0, a2, 9
116 	bnez	t0, __memcpy_small
117 
118 	add.d	a3, a1, a2
119 	add.d	a2, a0, a2
120 	ld.d	a6, a1, 0
121 	ld.d	a7, a3, -8
122 
123 	/* align up destination address */
124 	andi	t1, a0, 7
125 	sub.d	t0, zero, t1
126 	addi.d	t0, t0, 8
127 	add.d	a1, a1, t0
128 	add.d	a5, a0, t0
129 
130 	addi.d	a4, a3, -64
131 	bgeu	a1, a4, .Llt64
132 
133 	/* copy 64 bytes at a time */
134 .Lloop64:
135 	ld.d	t0, a1, 0
136 	ld.d	t1, a1, 8
137 	ld.d	t2, a1, 16
138 	ld.d	t3, a1, 24
139 	ld.d	t4, a1, 32
140 	ld.d	t5, a1, 40
141 	ld.d	t6, a1, 48
142 	ld.d	t7, a1, 56
143 	addi.d	a1, a1, 64
144 	st.d	t0, a5, 0
145 	st.d	t1, a5, 8
146 	st.d	t2, a5, 16
147 	st.d	t3, a5, 24
148 	st.d	t4, a5, 32
149 	st.d	t5, a5, 40
150 	st.d	t6, a5, 48
151 	st.d	t7, a5, 56
152 	addi.d	a5, a5, 64
153 	bltu	a1, a4, .Lloop64
154 
155 	/* copy the remaining bytes */
156 .Llt64:
157 	addi.d	a4, a3, -32
158 	bgeu	a1, a4, .Llt32
159 	ld.d	t0, a1, 0
160 	ld.d	t1, a1, 8
161 	ld.d	t2, a1, 16
162 	ld.d	t3, a1, 24
163 	addi.d	a1, a1, 32
164 	st.d	t0, a5, 0
165 	st.d	t1, a5, 8
166 	st.d	t2, a5, 16
167 	st.d	t3, a5, 24
168 	addi.d	a5, a5, 32
169 
170 .Llt32:
171 	addi.d	a4, a3, -16
172 	bgeu	a1, a4, .Llt16
173 	ld.d	t0, a1, 0
174 	ld.d	t1, a1, 8
175 	addi.d	a1, a1, 16
176 	st.d	t0, a5, 0
177 	st.d	t1, a5, 8
178 	addi.d	a5, a5, 16
179 
180 .Llt16:
181 	addi.d	a4, a3, -8
182 	bgeu	a1, a4, .Llt8
183 	ld.d	t0, a1, 0
184 	st.d	t0, a5, 0
185 
186 .Llt8:
187 	st.d	a6, a0, 0
188 	st.d	a7, a2, -8
189 
190 	/* return */
191 	jr	ra
192 SYM_FUNC_END(__memcpy_fast)
193