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