summaryrefslogtreecommitdiffstats
path: root/main/glib/smemcpy.c
blob: 5b1747083abf60f877ff7f1b345244cff5fa69dd (plain) (blame)
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
#include "config.h"
#include <ctype.h>
#include "genlib.h"
#include "stddefs.h"

/* s_memcpy():
 *	Superset of memcpy().  Note, this used to be tfsmemcpy() in tfs.c;
 *  however, since it has no real TFS dependencies, and code outside of
 *  TFS uses it, it has been moved here and the name is changed.
 *
 *  Includes verbose option plus verification after copy.
 *  Takes advantage of address alignment when possible.
 *
 *  Note:
 *  If verbose is greater than one, then this function doesn't
 *  do any memory transfer, it simply displays the memory range
 *  that is to be transferred.  This is used by TFS to dump a map without
 *  actually touching memory.
 * 
 *  Return:
 *  0 if successful, else -1 indicating some part of the copy failed.
 */
int
s_memcpy(char *_to,char *_from,int count, int verbose,int verifyonly)
{
	int	err;
	volatile register char *to, *from, *end;

	to = _to;
	from = _from;

	if (verbose)
		printf("%s %7d bytes from 0x%08lx to 0x%08lx",
			verifyonly ? "vrfy" : "copy", count,(ulong)from,(ulong)to);

	if (_to == _from) {
		if (verbose)
			printf("\n");
		return(0);
	}

	if (count < 0)
		return(-1);

	if (verifyonly) {
		while(count) {
			if (*to != *from)
				break;
			to++;
			from++;
			count--;
#ifdef WATCHDOG_ENABLED
			if ((count & 0xff) == 0)
				WATCHDOG_MACRO;
#endif
		}
		if (count) {
			if (verbose) {
				printf(" FAILED\n");
				printf("            (0x%02x @ 0x%08lx should be 0x%02x)\n",
					*to,(ulong)to,*from);
			}
			return(-1);
		}
		else
			if (verbose)
				printf(" OK\n");
			return(0);
	}

	/* If verbose is greater than 1, then we don't even do a memcpy,
	 * we just let the user know what we would have done...
	 */
	if ((count == 0) || (verbose > 1))
		goto done;

	if (to != from) {

		err = 0;
		if (!((int)to & 3) && !((int)from & 3) && !(count & 3)) {
			volatile register ulong	*lto, *lfrom, *lend;
	
			count >>= 2;
			lto = (ulong *)to;
			lfrom = (ulong *)from;
			lend = lto + count;
			while(lto < lend) {
				*lto = *lfrom;
				if (*lto != *lfrom) {
					err = 1;
					break;
				}
				lto++;
				lfrom++;
#ifdef WATCHDOG_ENABLED
				if (((int)lto & 0xff) == 0)
					WATCHDOG_MACRO;
#endif
			}
		}
		else if (!((int)to & 1) && !((int)from & 1) && !(count & 1)) {
			volatile register ushort	*sto, *sfrom, *send;
	
			count >>= 1;
			sto = (ushort *)to;
			sfrom = (ushort *)from;
			send = sto + count;
			while(sto < send) {
				*sto = *sfrom;
				if (*sto != *sfrom) {
					err = 1;
					break;
				}
				sto++;
				sfrom++;
#ifdef WATCHDOG_ENABLED
				if (((int)sto & 0xff) == 0)
					WATCHDOG_MACRO;
#endif
			}
		}
		else {
			end = to + count;
			while(to < end) {
				*to = *from;
				if (*to != *from) {
					err = 1;
					break;
				}
				to++;
				from++;
#ifdef WATCHDOG_ENABLED
				if (((int)to & 0xff) == 0)
					WATCHDOG_MACRO;
#endif
			}
		}
		if (err) {
			if (verbose)
				printf(" failed\n");
			return(-1);
		}
	}

done:
	if (verbose)
		printf("\n");

	return(0);
}