]> git.saurik.com Git - apple/boot.git/blob - gen/libsa/memset.c
boot-111.tar.gz
[apple/boot.git] / gen / libsa / memset.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /* Copyright (c) 1991 NeXT Computer, Inc. All rights reserved.
26 *
27 * File: libc/i386/ansi/memset.c
28 * Author: Bruce Martin, NeXT Computer, Inc.
29 *
30 * This file contains machine dependent code for block compares
31 * on NeXT i386-based products. Currently tuned for the i486.
32 *
33 * This code is loosely based on some work done by Mike DeMoney
34 * for the m88k.
35 *
36 * HISTORY
37 * 14-Dec-93 Curtis Galloway
38 * Modified for the booter; simplified simple_char_set.
39 *
40 * 14-Aug-92 Bruce Martin (Bruce_Martin@NeXT.COM)
41 * Created.
42 */
43
44 #define MIN_TO_ALIGN 32
45
46 /*
47 * Convert a void * into a unsigned int so arithmetic can be done
48 * (Technically, the gnu C compiler is tolerant of arithmetic
49 * on void *, but ansi isn't; so we do this.)
50 */
51 #define UNS(voidp) ((unsigned int)(voidp))
52
53 /*
54 * Number of bytes addr is past an object of 'align' size.
55 */
56 #define BYTES_PAST_ALIGNMENT(voidp, align) \
57 (UNS(voidp) & (align - 1))
58
59 /*
60 * Bytes moved by an unrolled loop
61 */
62 #define LOOP_STRIDE(type, unroll) ((unroll) * sizeof(type))
63
64
65 /*
66 * Len modulo LOOP_STRIDE
67 */
68 #define MODULO_LOOP_UNROLL(len, type, unroll) \
69 ((len) & (LOOP_STRIDE(type, unroll) - 1) & ~(sizeof(type) - 1))
70
71
72 /*
73 * Convert a void * + offset into char, short, int, or long long reference
74 * based at that address
75 */
76 #define CHAR(voidp, offset) (*(char *)(UNS(voidp) + (offset)))
77 #define SHORT(voidp, offset) (*(short *)(UNS(voidp) + (offset)))
78 #define INT(voidp, offset) (*(int *)(UNS(voidp) + (offset)))
79
80
81
82 static inline void
83 simple_char_set(char *dst, int val, int len)
84 {
85 asm("rep; stosb"
86 : /* no outputs */
87 : "&c" (len), "D" (dst), "a" (val)
88 : "ecx", "edi", "eax");
89 }
90
91
92
93 void *memset(void *, int, unsigned long);
94
95 int bzero(void *dst, unsigned long ulen)
96 {
97 (void) memset(dst, 0, ulen);
98 return 0;
99 }
100
101
102 void *memset(void *dst, int val, unsigned long ulen)
103 {
104 int len = ulen;
105 void *orig_dst = dst;
106 int need_to_set;
107 int alignment;
108
109 val |= (val << 8);
110 val |= (val << 16);
111
112 /* Always do a forward copy */
113
114 if (len < MIN_TO_ALIGN) {
115 simple_char_set(dst, val, len);
116 return orig_dst;
117 }
118
119 if (need_to_set = BYTES_PAST_ALIGNMENT(dst, 2 * sizeof(int))) {
120 need_to_set = (2 * sizeof(int)) - need_to_set;
121 simple_char_set(dst, val, need_to_set);
122 len -= need_to_set;
123 UNS(dst) += need_to_set;
124 }
125
126 alignment = MODULO_LOOP_UNROLL(len, int, 8);
127 UNS(dst) += alignment - LOOP_STRIDE(int, 8);
128 switch (alignment) {
129 do {
130 INT(dst, 0) = val;
131 case 28: INT(dst, 4) = val;
132 case 24: INT(dst, 8) = val;
133 case 20: INT(dst, 12) = val;
134 case 16: INT(dst, 16) = val;
135 case 12: INT(dst, 20) = val;
136 case 8: INT(dst, 24) = val;
137 case 4: INT(dst, 28) = val;
138 case 0:
139 UNS(dst) += LOOP_STRIDE(int, 8);
140 len -= LOOP_STRIDE(int, 8);
141 } while (len >= 0);
142 len &= sizeof(int) - 1;
143 }
144
145 switch (len) {
146 case 3: CHAR(dst, 2) = val;
147 case 2: CHAR(dst, 1) = val;
148 case 1: CHAR(dst, 0) = val;
149 }
150
151 return orig_dst;
152 }