1/*	$NetBSD: bcopy.c,v 1.9 2009/03/18 12:25:06 tsutsui Exp $	*/
2
3/*-
4 * Copyright (c) 1990, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Chris Torek.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35#include <sys/cdefs.h>
36#if defined(LIBC_SCCS) && !defined(lint)
37#if 0
38static char sccsid[] = "@(#)bcopy.c	8.1 (Berkeley) 6/4/93";
39#else
40__RCSID("$NetBSD: bcopy.c,v 1.9 2009/03/18 12:25:06 tsutsui Exp $");
41#endif
42#endif /* LIBC_SCCS and not lint */
43
44#if !defined(_KERNEL) && !defined(_STANDALONE)
45#include <assert.h>
46#include <string.h>
47#else
48#include <lib/libkern/libkern.h>
49#if !defined(MEMCOPY) && defined(_STANDALONE)
50#include <lib/libsa/stand.h>
51#endif
52#endif
53
54#ifdef _FORTIFY_SOURCE
55#undef bcopy
56#undef memcpy
57#undef memmove
58#endif
59
60#ifndef __OPTIMIZE_SIZE__
61/*
62 * sizeof(word) MUST BE A POWER OF TWO
63 * SO THAT wmask BELOW IS ALL ONES
64 */
65typedef	long word;		/* "word" used for optimal copy speed */
66
67#define	wsize	sizeof(word)
68#define	wmask	(wsize - 1)
69
70/*
71 * Copy a block of memory, handling overlap.
72 * This is the routine that actually implements
73 * (the portable versions of) bcopy, memcpy, and memmove.
74 */
75#if defined(MEMCOPY)
76void *
77memcpy(void *dst0, const void *src0, size_t length)
78#elif defined(MEMMOVE)
79void *
80memmove(void *dst0, const void *src0, size_t length)
81#else
82void
83bcopy(const void *src0, void *dst0, size_t length)
84#endif
85{
86	char *dst = dst0;
87	const char *src = src0;
88	size_t t;
89	unsigned long u;
90
91#if !defined(_KERNEL)
92	_DIAGASSERT(dst0 != 0);
93	_DIAGASSERT(src0 != 0);
94#endif
95
96	if (length == 0 || dst == src)		/* nothing to do */
97		goto done;
98
99	/*
100	 * Macros: loop-t-times; and loop-t-times, t>0
101	 */
102#define	TLOOP(s) if (t) TLOOP1(s)
103#define	TLOOP1(s) do { s; } while (--t)
104
105	if ((unsigned long)dst < (unsigned long)src) {
106		/*
107		 * Copy forward.
108		 */
109		u = (unsigned long)src;	/* only need low bits */
110		if ((u | (unsigned long)dst) & wmask) {
111			/*
112			 * Try to align operands.  This cannot be done
113			 * unless the low bits match.
114			 */
115			if ((u ^ (unsigned long)dst) & wmask || length < wsize)
116				t = length;
117			else
118				t = wsize - (size_t)(u & wmask);
119			length -= t;
120			TLOOP1(*dst++ = *src++);
121		}
122		/*
123		 * Copy whole words, then mop up any trailing bytes.
124		 */
125		t = length / wsize;
126		TLOOP(*(word *)(void *)dst = *(const word *)(const void *)src; src += wsize; dst += wsize);
127		t = length & wmask;
128		TLOOP(*dst++ = *src++);
129	} else {
130		/*
131		 * Copy backwards.  Otherwise essentially the same.
132		 * Alignment works as before, except that it takes
133		 * (t&wmask) bytes to align, not wsize-(t&wmask).
134		 */
135		src += length;
136		dst += length;
137		_DIAGASSERT((unsigned long)dst >= (unsigned long)dst0);
138		_DIAGASSERT((unsigned long)src >= (unsigned long)src0);
139		u = (unsigned long)src;
140		if ((u | (unsigned long)dst) & wmask) {
141			if ((u ^ (unsigned long)dst) & wmask || length <= wsize)
142				t = length;
143			else
144				t = (size_t)(u & wmask);
145			length -= t;
146			TLOOP1(*--dst = *--src);
147		}
148		t = length / wsize;
149		TLOOP(src -= wsize; dst -= wsize; *(word *)(void *)dst = *(const word *)(const void *)src);
150		t = length & wmask;
151		TLOOP(*--dst = *--src);
152	}
153done:
154#if defined(MEMCOPY) || defined(MEMMOVE)
155	return (dst0);
156#else
157	return;
158#endif
159}
160#else /* __OPTIMIZE_SIZE__ */
161#if defined(MEMCOPY)
162/*
163 * This is designed to be small, not fast.
164 */
165void *
166memcpy(void *s1, const void *s2, size_t n)
167{
168	const char *f = s2;
169	char *t = s1;
170
171	while (n-- > 0)
172		*t++ = *f++;
173	return s1;
174}
175#elif defined(MEMMOVE)
176/*
177 * This is designed to be small, not fast.
178 */
179void *
180memmove(void *s1, const void *s2, size_t n)
181{
182	const char *f = s2;
183	char *t = s1;
184
185	if (f < t) {
186		f += n;
187		t += n;
188		while (n-- > 0)
189			*--t = *--f;
190	} else {
191		while (n-- > 0)
192			*t++ = *f++;
193	}
194	return s1;
195}
196#else
197/*
198 * This is designed to be small, not fast.
199 */
200void
201bcopy(const void *s2, void *s1, size_t n)
202{
203	const char *f = s2;
204	char *t = s1;
205
206	while (n-- > 0)
207		*t++ = *f++;
208}
209#endif
210#endif /* __OPTIMIZE_SIZE__ */
211