xref: /illumos-gate/usr/src/common/hdcrc/hd_crc.h (revision 635216b673cf196ac523ff2a7ab715717e553292)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2009, Intel Corporation.
24  * All rights reserved.
25  */
26 
27 /*
28  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
29  * Use is subject to license terms.
30  */
31 
32 #ifndef	_CRC_HD_H
33 #define	_CRC_HD_H
34 
35 #ifdef __cplusplus
36 extern "C" {
37 #endif
38 
39 #include <sys/types.h>
40 
41 #ifdef __cplusplus
42 #ifndef INLINE
43 #define	INLINE inline
44 #endif
45 #else
46 #ifndef INLINE
47 #define	INLINE
48 #endif
49 #endif
50 
51 #if defined(__i386) || defined(__amd_64) || defined(__x86_64)
52 
53 #define	INTEL_CPU_FEATURE_SSE42	0x0100000
54 
55 static INLINE unsigned int
56 #ifdef _KERNEL
57 /*LINTED:E_FUNC_ARG_UNUSED*/
58 cpuid_ecx(unsigned int op)
59 #else
60 cpuid_ecx(unsigned int op)
61 #endif /* _KERNEL */
62 {
63 	/*LINTED:E_FUNC_VAR_UNUSED*/
64 	unsigned int eax, ecx;
65 	__asm__ __volatile__("cpuid"
66 	    : "=a" (eax), "=c" (ecx)
67 	    : "0" (op)
68 	    : "bx", "dx");
69 	/*LINTED:E_VAR_USED_BEFORE_SET*/
70 	return (ecx);
71 }
72 
73 static INLINE uint32_t
74 #ifdef _KERNEL
75 /*LINTED:E_FUNC_ARG_UNUSED*/
76 mm_crc32_u8(uint32_t crc, uint8_t *data)
77 #else
78 mm_crc32_u8(uint32_t crc, uint8_t *data)
79 #endif /* _KERNEL */
80 {
81 	__asm__ __volatile__(
82 	    /* "crc32 r32, r/m8" */
83 	    ".byte 0xF2, 0x0F, 0x38, 0xF0, 0xF1"
84 	    : "=S" (crc)
85 	    : "0" (crc), "c" (*data));
86 
87 	return (crc);
88 }
89 
90 #if defined(__amd64) || defined(__x86_64)
91 
92 static INLINE uint32_t
93 #ifdef _KERNEL
94 /*LINTED:E_FUNC_ARG_UNUSED*/
95 mm_crc32_u64(uint32_t crc, uint64_t *data)
96 #else
97 mm_crc32_u64(uint32_t crc, uint64_t *data)
98 #endif /* _KERNEL */
99 {
100 	__asm__ __volatile__(
101 	    /* "crc32 r32, r/m64" */
102 	    ".byte 0xF2, 0x48, 0x0F, 0x38, 0xF1, 0xF1"
103 	    : "=S" (crc)
104 	    : "0" (crc), "c" (*data));
105 
106 	return (crc);
107 }
108 
109 #define	INTEL_CRC_ALIGN_MASK 0x7
110 #define	INTEL_CRC_SIZE 8
111 #define	INTEL_CRC_DATA_TYPE uint64_t
112 #define	INTEL_CRC_FUNC mm_crc32_u64
113 
114 #else
115 
116 static INLINE uint32_t
117 #ifdef _KERNEL
118 /*LINTED:E_FUNC_ARG_UNUSED*/
119 mm_crc32_u32(uint32_t crc, uint32_t *data)
120 #else
121 mm_crc32_u32(uint32_t crc, uint32_t *data)
122 #endif /* _KERNEL */
123 {
124 	__asm__ __volatile__(
125 	    /* "crc32 r32, r/m32" */
126 	    ".byte 0xF2, 0x0F, 0x38, 0xF1, 0xF1"
127 	    : "=S" (crc)
128 	    : "0" (crc), "c" (*data));
129 
130 	return (crc);
131 }
132 
133 #define	INTEL_CRC_ALIGN_MASK 0x3
134 #define	INTEL_CRC_SIZE 4
135 #define	INTEL_CRC_DATA_TYPE uint32_t
136 #define	INTEL_CRC_FUNC mm_crc32_u32
137 
138 #endif
139 
140 static INLINE uint32_t
141 intel_crc32c(uint8_t *address, unsigned long length, uint32_t crc)
142 {
143 	uint32_t i = (uintptr_t)address & INTEL_CRC_ALIGN_MASK;
144 	uint8_t *data = address;
145 
146 	/* Process unaligned header data */
147 	while ((length > 0) && (i > 0)) {
148 		crc = mm_crc32_u8(crc, data);
149 		++ data;
150 		-- length;
151 		i ++;
152 		i &= INTEL_CRC_ALIGN_MASK;
153 	}
154 
155 	/* aligned data part */
156 	while (length >= INTEL_CRC_SIZE) {
157 		/*LINTED:E_BAD_PTR_CAST_ALIGN*/
158 		crc = INTEL_CRC_FUNC(crc, (INTEL_CRC_DATA_TYPE *)data);
159 		data += INTEL_CRC_SIZE;
160 		length -= INTEL_CRC_SIZE;
161 	}
162 
163 	/* unaligned tail data */
164 	while (length > 0) {
165 		crc = mm_crc32_u8(crc, data);
166 		++ data;
167 		-- length;
168 	}
169 
170 	return (crc ^ 0xFFFFFFFF);
171 }
172 
173 #define	HW_CRC32(buffer, length, crc) (intel_crc32c((buffer), (length), (crc)))
174 #define	HW_CRC32_CONT(buffer, length, crc) \
175 	(intel_crc32c((buffer), (length), (crc) ^ 0xFFFFFFFF))
176 #else
177 #define	HW_CRC32(buffer, length, crc)		0
178 #define	HW_CRC32_CONT(buffer, length, crc)	0
179 #endif
180 
181 static INLINE boolean_t
182 #if defined(_KERNEL) && !defined(__i386) && !defined(__amd_64) &&\
183 	!defined(__x86_64)
184 /*LINTED:E_FUNC_ARG_UNUSED*/
185 hd_crc32_avail(uint32_t *crc32_table)
186 #else
187 hd_crc32_avail(uint32_t *crc32_table)
188 #endif
189 {
190 #if defined(__i386) || defined(__amd_64) || defined(__x86_64)
191 	int i;
192 	/* poly = 0x1EDC6F41 */
193 	static const uint32_t _intel_crc32_hd_table[256] = {
194 		0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4,
195 		0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
196 		0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B,
197 		0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,
198 		0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B,
199 		0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384,
200 		0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54,
201 		0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B,
202 		0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A,
203 		0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,
204 		0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5,
205 		0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA,
206 		0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45,
207 		0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A,
208 		0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A,
209 		0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595,
210 		0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48,
211 		0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957,
212 		0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687,
213 		0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,
214 		0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927,
215 		0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38,
216 		0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8,
217 		0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7,
218 		0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096,
219 		0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789,
220 		0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859,
221 		0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46,
222 		0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9,
223 		0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,
224 		0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36,
225 		0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829,
226 		0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C,
227 		0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93,
228 		0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043,
229 		0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C,
230 		0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3,
231 		0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC,
232 		0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C,
233 		0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,
234 		0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652,
235 		0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D,
236 		0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D,
237 		0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982,
238 		0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D,
239 		0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622,
240 		0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2,
241 		0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED,
242 		0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530,
243 		0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,
244 		0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF,
245 		0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0,
246 		0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F,
247 		0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540,
248 		0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90,
249 		0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F,
250 		0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE,
251 		0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1,
252 		0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321,
253 		0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,
254 		0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81,
255 		0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
256 		0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E,
257 		0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351
258 	};
259 
260 	if ((cpuid_ecx(1) & INTEL_CPU_FEATURE_SSE42) != 0) {
261 		for (i = 0; i < 256; i++) {
262 			if (crc32_table[i] != _intel_crc32_hd_table[i])
263 				return (B_FALSE);
264 		}
265 		return (B_TRUE);
266 	}
267 #endif
268 	return (B_FALSE);
269 }
270 
271 #ifdef __cplusplus
272 }
273 #endif
274 
275 #endif /* _CRC_HD_H */
276