1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
| /*
| * linux/arch/unicore32/lib/copy_template.S
| *
| * Code specific to PKUnity SoC and UniCore ISA
| *
| * Copyright (C) 2001-2010 GUAN Xue-tao
| *
| * This program is free software; you can redistribute it and/or modify
| * it under the terms of the GNU General Public License version 2 as
| * published by the Free Software Foundation.
| */
|
| /*
| * Theory of operation
| * -------------------
| *
| * This file provides the core code for a forward memory copy used in
| * the implementation of memcopy(), copy_to_user() and copy_from_user().
| *
| * The including file must define the following accessor macros
| * according to the need of the given function:
| *
| * ldr1w ptr reg abort
| *
| * This loads one word from 'ptr', stores it in 'reg' and increments
| * 'ptr' to the next word. The 'abort' argument is used for fixup tables.
| *
| * ldr4w ptr reg1 reg2 reg3 reg4 abort
| * ldr8w ptr, reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
| *
| * This loads four or eight words starting from 'ptr', stores them
| * in provided registers and increments 'ptr' past those words.
| * The'abort' argument is used for fixup tables.
| *
| * ldr1b ptr reg cond abort
| *
| * Similar to ldr1w, but it loads a byte and increments 'ptr' one byte.
| * It also must apply the condition code if provided, otherwise the
| * "al" condition is assumed by default.
| *
| * str1w ptr reg abort
| * str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
| * str1b ptr reg cond abort
| *
| * Same as their ldr* counterparts, but data is stored to 'ptr' location
| * rather than being loaded.
| *
| * enter
| *
| * Preserve the provided registers on the stack plus any additional
| * data as needed by the implementation including this code. Called
| * upon code entry.
| *
| * exit
| *
| * Restore registers with the values previously saved with the
| * 'preserv' macro. Called upon code termination.
| */
|
|
| enter
|
| sub.a r2, r2, #4
| bsl 8f
| and.a ip, r0, #3
| bne 9f
| and.a ip, r1, #3
| bne 10f
|
| 1: sub.a r2, r2, #(28)
| stm.w (r5 - r8), [sp-]
| bsl 5f
|
| 3:
| 4: ldr8w r1, r3, r4, r5, r6, r7, r8, r10, r11, abort=20f
| sub.a r2, r2, #32
| str8w r0, r3, r4, r5, r6, r7, r8, r10, r11, abort=20f
| beg 3b
|
| 5: and.a ip, r2, #28
| rsub ip, ip, #32
| beq 7f
| add pc, pc, ip @ C is always clear here
| nop
|
| ldr1w r1, r3, abort=20f
| ldr1w r1, r4, abort=20f
| ldr1w r1, r5, abort=20f
| ldr1w r1, r6, abort=20f
| ldr1w r1, r7, abort=20f
| ldr1w r1, r8, abort=20f
| ldr1w r1, r11, abort=20f
|
| add pc, pc, ip
| nop
|
| str1w r0, r3, abort=20f
| str1w r0, r4, abort=20f
| str1w r0, r5, abort=20f
| str1w r0, r6, abort=20f
| str1w r0, r7, abort=20f
| str1w r0, r8, abort=20f
| str1w r0, r11, abort=20f
|
| 7: ldm.w (r5 - r8), [sp]+
|
| 8: mov.a r2, r2 << #31
| ldr1b r1, r3, ne, abort=21f
| ldr1b r1, r4, ea, abort=21f
| ldr1b r1, r10, ea, abort=21f
| str1b r0, r3, ne, abort=21f
| str1b r0, r4, ea, abort=21f
| str1b r0, r10, ea, abort=21f
|
| exit
|
| 9: rsub ip, ip, #4
| csub.a ip, #2
| ldr1b r1, r3, sg, abort=21f
| ldr1b r1, r4, eg, abort=21f
| ldr1b r1, r11, abort=21f
| str1b r0, r3, sg, abort=21f
| str1b r0, r4, eg, abort=21f
| sub.a r2, r2, ip
| str1b r0, r11, abort=21f
| bsl 8b
| and.a ip, r1, #3
| beq 1b
|
| 10: andn r1, r1, #3
| csub.a ip, #2
| ldr1w r1, r11, abort=21f
| beq 17f
| bsg 18f
|
|
| .macro forward_copy_shift a b
|
| sub.a r2, r2, #28
| bsl 14f
|
| 11: stm.w (r5 - r9), [sp-]
|
| 12:
| ldr4w r1, r4, r5, r6, r7, abort=19f
| mov r3, r11 pull #\a
| sub.a r2, r2, #32
| ldr4w r1, r8, r9, r10, r11, abort=19f
| or r3, r3, r4 push #\b
| mov r4, r4 pull #\a
| or r4, r4, r5 push #\b
| mov r5, r5 pull #\a
| or r5, r5, r6 push #\b
| mov r6, r6 pull #\a
| or r6, r6, r7 push #\b
| mov r7, r7 pull #\a
| or r7, r7, r8 push #\b
| mov r8, r8 pull #\a
| or r8, r8, r9 push #\b
| mov r9, r9 pull #\a
| or r9, r9, r10 push #\b
| mov r10, r10 pull #\a
| or r10, r10, r11 push #\b
| str8w r0, r3, r4, r5, r6, r7, r8, r9, r10, , abort=19f
| beg 12b
|
| ldm.w (r5 - r9), [sp]+
|
| 14: and.a ip, r2, #28
| beq 16f
|
| 15: mov r3, r11 pull #\a
| ldr1w r1, r11, abort=21f
| sub.a ip, ip, #4
| or r3, r3, r11 push #\b
| str1w r0, r3, abort=21f
| bsg 15b
|
| 16: sub r1, r1, #(\b / 8)
| b 8b
|
| .endm
|
|
| forward_copy_shift a=8 b=24
|
| 17: forward_copy_shift a=16 b=16
|
| 18: forward_copy_shift a=24 b=8
|
|
| /*
| * Abort preamble and completion macros.
| * If a fixup handler is required then those macros must surround it.
| * It is assumed that the fixup code will handle the private part of
| * the exit macro.
| */
|
| .macro copy_abort_preamble
| 19: ldm.w (r5 - r9), [sp]+
| b 21f
| 299: .word 0 @ store lr
| @ to avoid function call in fixup
| 20: ldm.w (r5 - r8), [sp]+
| 21:
| adr r1, 299b
| stw lr, [r1]
| .endm
|
| .macro copy_abort_end
| adr lr, 299b
| ldw pc, [lr]
| .endm
|
|