Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/microblaze/lib/memmove.c
10817 views
1
/*
2
* Copyright (C) 2008-2009 Michal Simek <[email protected]>
3
* Copyright (C) 2008-2009 PetaLogix
4
* Copyright (C) 2007 John Williams
5
*
6
* Reasonably optimised generic C-code for memcpy on Microblaze
7
* This is generic C code to do efficient, alignment-aware memmove.
8
*
9
* It is based on demo code originally Copyright 2001 by Intel Corp, taken from
10
* http://www.embedded.com/showArticle.jhtml?articleID=19205567
11
*
12
* Attempts were made, unsuccessfully, to contact the original
13
* author of this code (Michael Morrow, Intel). Below is the original
14
* copyright notice.
15
*
16
* This software has been developed by Intel Corporation.
17
* Intel specifically disclaims all warranties, express or
18
* implied, and all liability, including consequential and
19
* other indirect damages, for the use of this program, including
20
* liability for infringement of any proprietary rights,
21
* and including the warranties of merchantability and fitness
22
* for a particular purpose. Intel does not assume any
23
* responsibility for and errors which may appear in this program
24
* not any responsibility to update it.
25
*/
26
27
#include <linux/types.h>
28
#include <linux/stddef.h>
29
#include <linux/compiler.h>
30
#include <linux/module.h>
31
#include <linux/string.h>
32
33
#ifdef __HAVE_ARCH_MEMMOVE
34
#ifndef CONFIG_OPT_LIB_FUNCTION
35
void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
36
{
37
const char *src = v_src;
38
char *dst = v_dst;
39
40
if (!c)
41
return v_dst;
42
43
/* Use memcpy when source is higher than dest */
44
if (v_dst <= v_src)
45
return memcpy(v_dst, v_src, c);
46
47
/* copy backwards, from end to beginning */
48
src += c;
49
dst += c;
50
51
/* Simple, byte oriented memmove. */
52
while (c--)
53
*--dst = *--src;
54
55
return v_dst;
56
}
57
#else /* CONFIG_OPT_LIB_FUNCTION */
58
void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
59
{
60
const char *src = v_src;
61
char *dst = v_dst;
62
const uint32_t *i_src;
63
uint32_t *i_dst;
64
65
if (!c)
66
return v_dst;
67
68
/* Use memcpy when source is higher than dest */
69
if (v_dst <= v_src)
70
return memcpy(v_dst, v_src, c);
71
72
/* The following code tries to optimize the copy by using unsigned
73
* alignment. This will work fine if both source and destination are
74
* aligned on the same boundary. However, if they are aligned on
75
* different boundaries shifts will be necessary. This might result in
76
* bad performance on MicroBlaze systems without a barrel shifter.
77
*/
78
/* FIXME this part needs more test */
79
/* Do a descending copy - this is a bit trickier! */
80
dst += c;
81
src += c;
82
83
if (c >= 4) {
84
unsigned value, buf_hold;
85
86
/* Align the destination to a word boundary. */
87
/* This is done in an endian independent manner. */
88
89
switch ((unsigned long)dst & 3) {
90
case 3:
91
*--dst = *--src;
92
--c;
93
case 2:
94
*--dst = *--src;
95
--c;
96
case 1:
97
*--dst = *--src;
98
--c;
99
}
100
101
i_dst = (void *)dst;
102
/* Choose a copy scheme based on the source */
103
/* alignment relative to dstination. */
104
switch ((unsigned long)src & 3) {
105
case 0x0: /* Both byte offsets are aligned */
106
107
i_src = (const void *)src;
108
109
for (; c >= 4; c -= 4)
110
*--i_dst = *--i_src;
111
112
src = (const void *)i_src;
113
break;
114
case 0x1: /* Unaligned - Off by 1 */
115
/* Word align the source */
116
i_src = (const void *) (((unsigned)src + 4) & ~3);
117
#ifndef __MICROBLAZEEL__
118
/* Load the holding buffer */
119
buf_hold = *--i_src >> 24;
120
121
for (; c >= 4; c -= 4) {
122
value = *--i_src;
123
*--i_dst = buf_hold << 8 | value;
124
buf_hold = value >> 24;
125
}
126
#else
127
/* Load the holding buffer */
128
buf_hold = (*--i_src & 0xFF) << 24;
129
130
for (; c >= 4; c -= 4) {
131
value = *--i_src;
132
*--i_dst = buf_hold | ((value & 0xFFFFFF00)>>8);
133
buf_hold = (value & 0xFF) << 24;
134
}
135
#endif
136
/* Realign the source */
137
src = (const void *)i_src;
138
src += 1;
139
break;
140
case 0x2: /* Unaligned - Off by 2 */
141
/* Word align the source */
142
i_src = (const void *) (((unsigned)src + 4) & ~3);
143
#ifndef __MICROBLAZEEL__
144
/* Load the holding buffer */
145
buf_hold = *--i_src >> 16;
146
147
for (; c >= 4; c -= 4) {
148
value = *--i_src;
149
*--i_dst = buf_hold << 16 | value;
150
buf_hold = value >> 16;
151
}
152
#else
153
/* Load the holding buffer */
154
buf_hold = (*--i_src & 0xFFFF) << 16;
155
156
for (; c >= 4; c -= 4) {
157
value = *--i_src;
158
*--i_dst = buf_hold | ((value & 0xFFFF0000)>>16);
159
buf_hold = (value & 0xFFFF) << 16;
160
}
161
#endif
162
/* Realign the source */
163
src = (const void *)i_src;
164
src += 2;
165
break;
166
case 0x3: /* Unaligned - Off by 3 */
167
/* Word align the source */
168
i_src = (const void *) (((unsigned)src + 4) & ~3);
169
#ifndef __MICROBLAZEEL__
170
/* Load the holding buffer */
171
buf_hold = *--i_src >> 8;
172
173
for (; c >= 4; c -= 4) {
174
value = *--i_src;
175
*--i_dst = buf_hold << 24 | value;
176
buf_hold = value >> 8;
177
}
178
#else
179
/* Load the holding buffer */
180
buf_hold = (*--i_src & 0xFFFFFF) << 8;
181
182
for (; c >= 4; c -= 4) {
183
value = *--i_src;
184
*--i_dst = buf_hold | ((value & 0xFF000000)>> 24);
185
buf_hold = (value & 0xFFFFFF) << 8;
186
}
187
#endif
188
/* Realign the source */
189
src = (const void *)i_src;
190
src += 3;
191
break;
192
}
193
dst = (void *)i_dst;
194
}
195
196
/* simple fast copy, ... unless a cache boundary is crossed */
197
/* Finish off any remaining bytes */
198
switch (c) {
199
case 4:
200
*--dst = *--src;
201
case 3:
202
*--dst = *--src;
203
case 2:
204
*--dst = *--src;
205
case 1:
206
*--dst = *--src;
207
}
208
return v_dst;
209
}
210
#endif /* CONFIG_OPT_LIB_FUNCTION */
211
EXPORT_SYMBOL(memmove);
212
#endif /* __HAVE_ARCH_MEMMOVE */
213
214