Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/microblaze/lib/memcpy.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 memcpy.
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
32
#include <linux/string.h>
33
#include <asm/system.h>
34
35
#ifdef __HAVE_ARCH_MEMCPY
36
#ifndef CONFIG_OPT_LIB_FUNCTION
37
void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
38
{
39
const char *src = v_src;
40
char *dst = v_dst;
41
42
/* Simple, byte oriented memcpy. */
43
while (c--)
44
*dst++ = *src++;
45
46
return v_dst;
47
}
48
#else /* CONFIG_OPT_LIB_FUNCTION */
49
void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
50
{
51
const char *src = v_src;
52
char *dst = v_dst;
53
54
/* The following code tries to optimize the copy by using unsigned
55
* alignment. This will work fine if both source and destination are
56
* aligned on the same boundary. However, if they are aligned on
57
* different boundaries shifts will be necessary. This might result in
58
* bad performance on MicroBlaze systems without a barrel shifter.
59
*/
60
const uint32_t *i_src;
61
uint32_t *i_dst;
62
63
if (likely(c >= 4)) {
64
unsigned value, buf_hold;
65
66
/* Align the destination to a word boundary. */
67
/* This is done in an endian independent manner. */
68
switch ((unsigned long)dst & 3) {
69
case 1:
70
*dst++ = *src++;
71
--c;
72
case 2:
73
*dst++ = *src++;
74
--c;
75
case 3:
76
*dst++ = *src++;
77
--c;
78
}
79
80
i_dst = (void *)dst;
81
82
/* Choose a copy scheme based on the source */
83
/* alignment relative to destination. */
84
switch ((unsigned long)src & 3) {
85
case 0x0: /* Both byte offsets are aligned */
86
i_src = (const void *)src;
87
88
for (; c >= 4; c -= 4)
89
*i_dst++ = *i_src++;
90
91
src = (const void *)i_src;
92
break;
93
case 0x1: /* Unaligned - Off by 1 */
94
/* Word align the source */
95
i_src = (const void *) ((unsigned)src & ~3);
96
#ifndef __MICROBLAZEEL__
97
/* Load the holding buffer */
98
buf_hold = *i_src++ << 8;
99
100
for (; c >= 4; c -= 4) {
101
value = *i_src++;
102
*i_dst++ = buf_hold | value >> 24;
103
buf_hold = value << 8;
104
}
105
#else
106
/* Load the holding buffer */
107
buf_hold = (*i_src++ & 0xFFFFFF00) >>8;
108
109
for (; c >= 4; c -= 4) {
110
value = *i_src++;
111
*i_dst++ = buf_hold | ((value & 0xFF) << 24);
112
buf_hold = (value & 0xFFFFFF00) >>8;
113
}
114
#endif
115
/* Realign the source */
116
src = (const void *)i_src;
117
src -= 3;
118
break;
119
case 0x2: /* Unaligned - Off by 2 */
120
/* Word align the source */
121
i_src = (const void *) ((unsigned)src & ~3);
122
#ifndef __MICROBLAZEEL__
123
/* Load the holding buffer */
124
buf_hold = *i_src++ << 16;
125
126
for (; c >= 4; c -= 4) {
127
value = *i_src++;
128
*i_dst++ = buf_hold | value >> 16;
129
buf_hold = value << 16;
130
}
131
#else
132
/* Load the holding buffer */
133
buf_hold = (*i_src++ & 0xFFFF0000 )>>16;
134
135
for (; c >= 4; c -= 4) {
136
value = *i_src++;
137
*i_dst++ = buf_hold | ((value & 0xFFFF)<<16);
138
buf_hold = (value & 0xFFFF0000) >>16;
139
}
140
#endif
141
/* Realign the source */
142
src = (const void *)i_src;
143
src -= 2;
144
break;
145
case 0x3: /* Unaligned - Off by 3 */
146
/* Word align the source */
147
i_src = (const void *) ((unsigned)src & ~3);
148
#ifndef __MICROBLAZEEL__
149
/* Load the holding buffer */
150
buf_hold = *i_src++ << 24;
151
152
for (; c >= 4; c -= 4) {
153
value = *i_src++;
154
*i_dst++ = buf_hold | value >> 8;
155
buf_hold = value << 24;
156
}
157
#else
158
/* Load the holding buffer */
159
buf_hold = (*i_src++ & 0xFF000000) >> 24;
160
161
for (; c >= 4; c -= 4) {
162
value = *i_src++;
163
*i_dst++ = buf_hold | ((value & 0xFFFFFF) << 8);
164
buf_hold = (value & 0xFF000000) >> 24;
165
}
166
#endif
167
/* Realign the source */
168
src = (const void *)i_src;
169
src -= 1;
170
break;
171
}
172
dst = (void *)i_dst;
173
}
174
175
/* Finish off any remaining bytes */
176
/* simple fast copy, ... unless a cache boundary is crossed */
177
switch (c) {
178
case 3:
179
*dst++ = *src++;
180
case 2:
181
*dst++ = *src++;
182
case 1:
183
*dst++ = *src++;
184
}
185
186
return v_dst;
187
}
188
#endif /* CONFIG_OPT_LIB_FUNCTION */
189
EXPORT_SYMBOL(memcpy);
190
#endif /* __HAVE_ARCH_MEMCPY */
191
192