hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
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
214
215
216
217
218
219
220
221
222
223
224
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 *  linux/arch/arm/lib/memmove.S
 *
 *  Author:    Nicolas Pitre
 *  Created:    Sep 28, 2005
 *  Copyright:    (C) MontaVista Software Inc.
 */
 
#include <linux/linkage.h>
#include <asm/assembler.h>
#include <asm/unwind.h>
 
       .text
 
/*
 * Prototype: void *memmove(void *dest, const void *src, size_t n);
 *
 * Note:
 *
 * If the memory regions don't overlap, we simply branch to memcpy which is
 * normally a bit faster. Otherwise the copy is done going downwards.  This
 * is a transposition of the code from copy_template.S but with the copy
 * occurring in the opposite direction.
 */
 
ENTRY(memmove)
   UNWIND(    .fnstart            )
 
       subs    ip, r0, r1
       cmphi    r2, ip
       bls    memcpy
 
       stmfd    sp!, {r0, r4, lr}
   UNWIND(    .fnend                )
 
   UNWIND(    .fnstart            )
   UNWIND(    .save    {r0, r4, lr}        ) @ in first stmfd block
       add    r1, r1, r2
       add    r0, r0, r2
       subs    r2, r2, #4
       blt    8f
       ands    ip, r0, #3
   PLD(    pld    [r1, #-4]        )
       bne    9f
       ands    ip, r1, #3
       bne    10f
 
1:        subs    r2, r2, #(28)
       stmfd    sp!, {r5 - r8}
   UNWIND(    .fnend                )
 
   UNWIND(    .fnstart            )
   UNWIND(    .save    {r0, r4, lr}        )
   UNWIND(    .save    {r5 - r8}        ) @ in second stmfd block
       blt    5f
 
   CALGN(    ands    ip, r0, #31        )
   CALGN(    sbcsne    r4, ip, r2        )  @ C is always set here
   CALGN(    bcs    2f            )
   CALGN(    adr    r4, 6f            )
   CALGN(    subs    r2, r2, ip        )  @ C is set here
   CALGN(    rsb    ip, ip, #32        )
   CALGN(    add    pc, r4, ip        )
 
   PLD(    pld    [r1, #-4]        )
2:    PLD(    subs    r2, r2, #96        )
   PLD(    pld    [r1, #-32]        )
   PLD(    blt    4f            )
   PLD(    pld    [r1, #-64]        )
   PLD(    pld    [r1, #-96]        )
 
3:    PLD(    pld    [r1, #-128]        )
4:        ldmdb    r1!, {r3, r4, r5, r6, r7, r8, ip, lr}
       subs    r2, r2, #32
       stmdb    r0!, {r3, r4, r5, r6, r7, r8, ip, lr}
       bge    3b
   PLD(    cmn    r2, #96            )
   PLD(    bge    4b            )
 
5:        ands    ip, r2, #28
       rsb    ip, ip, #32
       addne    pc, pc, ip        @ C is always clear here
       b    7f
6:        W(nop)
       W(ldr)    r3, [r1, #-4]!
       W(ldr)    r4, [r1, #-4]!
       W(ldr)    r5, [r1, #-4]!
       W(ldr)    r6, [r1, #-4]!
       W(ldr)    r7, [r1, #-4]!
       W(ldr)    r8, [r1, #-4]!
       W(ldr)    lr, [r1, #-4]!
 
       add    pc, pc, ip
       nop
       W(nop)
       W(str)    r3, [r0, #-4]!
       W(str)    r4, [r0, #-4]!
       W(str)    r5, [r0, #-4]!
       W(str)    r6, [r0, #-4]!
       W(str)    r7, [r0, #-4]!
       W(str)    r8, [r0, #-4]!
       W(str)    lr, [r0, #-4]!
 
   CALGN(    bcs    2b            )
 
7:        ldmfd    sp!, {r5 - r8}
   UNWIND(    .fnend                ) @ end of second stmfd block
 
   UNWIND(    .fnstart            )
   UNWIND(    .save    {r0, r4, lr}        ) @ still in first stmfd block
 
8:        movs    r2, r2, lsl #31
       ldrbne    r3, [r1, #-1]!
       ldrbcs    r4, [r1, #-1]!
       ldrbcs    ip, [r1, #-1]
       strbne    r3, [r0, #-1]!
       strbcs    r4, [r0, #-1]!
       strbcs    ip, [r0, #-1]
       ldmfd    sp!, {r0, r4, pc}
 
9:        cmp    ip, #2
       ldrbgt    r3, [r1, #-1]!
       ldrbge    r4, [r1, #-1]!
       ldrb    lr, [r1, #-1]!
       strbgt    r3, [r0, #-1]!
       strbge    r4, [r0, #-1]!
       subs    r2, r2, ip
       strb    lr, [r0, #-1]!
       blt    8b
       ands    ip, r1, #3
       beq    1b
 
10:        bic    r1, r1, #3
       cmp    ip, #2
       ldr    r3, [r1, #0]
       beq    17f
       blt    18f
   UNWIND(    .fnend                )
 
 
       .macro    backward_copy_shift push pull
 
   UNWIND(    .fnstart            )
   UNWIND(    .save    {r0, r4, lr}        ) @ still in first stmfd block
       subs    r2, r2, #28
       blt    14f
 
   CALGN(    ands    ip, r0, #31        )
   CALGN(    sbcsne    r4, ip, r2        )  @ C is always set here
   CALGN(    subcc    r2, r2, ip        )
   CALGN(    bcc    15f            )
 
11:        stmfd    sp!, {r5 - r9}
   UNWIND(    .fnend                )
 
   UNWIND(    .fnstart            )
   UNWIND(    .save    {r0, r4, lr}        )
   UNWIND(    .save    {r5 - r9}        ) @ in new second stmfd block
 
   PLD(    pld    [r1, #-4]        )
   PLD(    subs    r2, r2, #96        )
   PLD(    pld    [r1, #-32]        )
   PLD(    blt    13f            )
   PLD(    pld    [r1, #-64]        )
   PLD(    pld    [r1, #-96]        )
 
12:    PLD(    pld    [r1, #-128]        )
13:        ldmdb   r1!, {r7, r8, r9, ip}
       mov     lr, r3, lspush #\push
       subs    r2, r2, #32
       ldmdb   r1!, {r3, r4, r5, r6}
       orr     lr, lr, ip, lspull #\pull
       mov     ip, ip, lspush #\push
       orr     ip, ip, r9, lspull #\pull
       mov     r9, r9, lspush #\push
       orr     r9, r9, r8, lspull #\pull
       mov     r8, r8, lspush #\push
       orr     r8, r8, r7, lspull #\pull
       mov     r7, r7, lspush #\push
       orr     r7, r7, r6, lspull #\pull
       mov     r6, r6, lspush #\push
       orr     r6, r6, r5, lspull #\pull
       mov     r5, r5, lspush #\push
       orr     r5, r5, r4, lspull #\pull
       mov     r4, r4, lspush #\push
       orr     r4, r4, r3, lspull #\pull
       stmdb   r0!, {r4 - r9, ip, lr}
       bge    12b
   PLD(    cmn    r2, #96            )
   PLD(    bge    13b            )
 
       ldmfd    sp!, {r5 - r9}
   UNWIND(    .fnend                ) @ end of the second stmfd block
 
   UNWIND(    .fnstart            )
   UNWIND(    .save {r0, r4, lr}        ) @ still in first stmfd block
 
14:        ands    ip, r2, #28
       beq    16f
 
15:        mov     lr, r3, lspush #\push
       ldr    r3, [r1, #-4]!
       subs    ip, ip, #4
       orr    lr, lr, r3, lspull #\pull
       str    lr, [r0, #-4]!
       bgt    15b
   CALGN(    cmp    r2, #0            )
   CALGN(    bge    11b            )
 
16:        add    r1, r1, #(\pull / 8)
       b    8b
   UNWIND(    .fnend                )
 
       .endm
 
 
       backward_copy_shift    push=8    pull=24
 
17:        backward_copy_shift    push=16    pull=16
 
18:        backward_copy_shift    push=24    pull=8
 
ENDPROC(memmove)