xref: /illumos-gate/usr/src/common/hdcrc/hd_crc.h (revision 2a910fbb)
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 #ifdef _KERNEL
54 #include <sys/x86_archext.h>	/* x86_feature, X86_AES */
55 
56 #else
57 
58 #include <sys/auxv.h>		/* getisax() */
59 #include <sys/auxv_386.h>	/* AV_386_AES bit */
60 
61 #endif
62 
63 static INLINE uint32_t
64 #ifdef _KERNEL
65 /*LINTED:E_FUNC_ARG_UNUSED*/
66 mm_crc32_u8(uint32_t crc, uint8_t *data)
67 #else
68 mm_crc32_u8(uint32_t crc, uint8_t *data)
69 #endif /* _KERNEL */
70 {
71 	__asm__ __volatile__(
72 	    /* "crc32 r32, r/m8" */
73 	    ".byte 0xF2, 0x0F, 0x38, 0xF0, 0xF1"
74 	    : "=S" (crc)
75 	    : "0" (crc), "c" (*data));
76 
77 	return (crc);
78 }
79 
80 #if defined(__amd64) || defined(__x86_64)
81 
82 static INLINE uint32_t
83 #ifdef _KERNEL
84 /*LINTED:E_FUNC_ARG_UNUSED*/
85 mm_crc32_u64(uint32_t crc, uint64_t *data)
86 #else
87 mm_crc32_u64(uint32_t crc, uint64_t *data)
88 #endif /* _KERNEL */
89 {
90 	__asm__ __volatile__(
91 	    /* "crc32 r32, r/m64" */
92 	    ".byte 0xF2, 0x48, 0x0F, 0x38, 0xF1, 0xF1"
93 	    : "=S" (crc)
94 	    : "0" (crc), "c" (*data));
95 
96 	return (crc);
97 }
98 
99 #define	INTEL_CRC_ALIGN_MASK 0x7
100 #define	INTEL_CRC_SIZE 8
101 #define	INTEL_CRC_DATA_TYPE uint64_t
102 #define	INTEL_CRC_FUNC mm_crc32_u64
103 
104 #else
105 
106 static INLINE uint32_t
107 #ifdef _KERNEL
108 /*LINTED:E_FUNC_ARG_UNUSED*/
109 mm_crc32_u32(uint32_t crc, uint32_t *data)
110 #else
111 mm_crc32_u32(uint32_t crc, uint32_t *data)
112 #endif /* _KERNEL */
113 {
114 	__asm__ __volatile__(
115 	    /* "crc32 r32, r/m32" */
116 	    ".byte 0xF2, 0x0F, 0x38, 0xF1, 0xF1"
117 	    : "=S" (crc)
118 	    : "0" (crc), "c" (*data));
119 
120 	return (crc);
121 }
122 
123 #define	INTEL_CRC_ALIGN_MASK 0x3
124 #define	INTEL_CRC_SIZE 4
125 #define	INTEL_CRC_DATA_TYPE uint32_t
126 #define	INTEL_CRC_FUNC mm_crc32_u32
127 
128 #endif
129 
130 static INLINE uint32_t
131 intel_crc32c(uint8_t *address, unsigned long length, uint32_t crc)
132 {
133 	uint32_t i = (uintptr_t)address & INTEL_CRC_ALIGN_MASK;
134 	uint8_t *data = address;
135 
136 	/* Process unaligned header data */
137 	while ((length > 0) && (i > 0)) {
138 		crc = mm_crc32_u8(crc, data);
139 		++ data;
140 		-- length;
141 		i ++;
142 		i &= INTEL_CRC_ALIGN_MASK;
143 	}
144 
145 	/* aligned data part */
146 	while (length >= INTEL_CRC_SIZE) {
147 		/*LINTED:E_BAD_PTR_CAST_ALIGN*/
148 		crc = INTEL_CRC_FUNC(crc, (INTEL_CRC_DATA_TYPE *)data);
149 		data += INTEL_CRC_SIZE;
150 		length -= INTEL_CRC_SIZE;
151 	}
152 
153 	/* unaligned tail data */
154 	while (length > 0) {
155 		crc = mm_crc32_u8(crc, data);
156 		++ data;
157 		-- length;
158 	}
159 
160 	return (crc ^ 0xFFFFFFFF);
161 }
162 
163 #define	HW_CRC32(buffer, length, crc) (intel_crc32c((buffer), (length), (crc)))
164 #define	HW_CRC32_CONT(buffer, length, crc) \
165 	(intel_crc32c((buffer), (length), (crc) ^ 0xFFFFFFFF))
166 #else
167 #define	HW_CRC32(buffer, length, crc)		0
168 #define	HW_CRC32_CONT(buffer, length, crc)	0
169 #endif
170 
171 static INLINE boolean_t
172 #if defined(_KERNEL) && !defined(__i386) && !defined(__amd_64) &&\
173 	!defined(__x86_64)
174 /*LINTED:E_FUNC_ARG_UNUSED*/
175 hd_crc32_avail(uint32_t *crc32_table)
176 #else
177 hd_crc32_avail(uint32_t *crc32_table)
178 #endif
179 {
180 #if defined(__i386) || defined(__amd_64) || defined(__x86_64)
181 	int i;
182 	/* poly = 0x1EDC6F41 */
183 	static const uint32_t _intel_crc32_hd_table[256] = {
184 		0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4,
185 		0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
186 		0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B,
187 		0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,
188 		0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B,
189 		0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384,
190 		0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54,
191 		0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B,
192 		0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A,
193 		0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,
194 		0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5,
195 		0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA,
196 		0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45,
197 		0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A,
198 		0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A,
199 		0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595,
200 		0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48,
201 		0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957,
202 		0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687,
203 		0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,
204 		0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927,
205 		0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38,
206 		0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8,
207 		0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7,
208 		0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096,
209 		0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789,
210 		0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859,
211 		0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46,
212 		0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9,
213 		0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,
214 		0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36,
215 		0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829,
216 		0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C,
217 		0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93,
218 		0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043,
219 		0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C,
220 		0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3,
221 		0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC,
222 		0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C,
223 		0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,
224 		0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652,
225 		0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D,
226 		0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D,
227 		0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982,
228 		0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D,
229 		0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622,
230 		0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2,
231 		0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED,
232 		0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530,
233 		0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,
234 		0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF,
235 		0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0,
236 		0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F,
237 		0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540,
238 		0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90,
239 		0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F,
240 		0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE,
241 		0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1,
242 		0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321,
243 		0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,
244 		0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81,
245 		0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
246 		0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E,
247 		0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351
248 	};
249 
250 #ifdef _KERNEL
251 	if (!(x86_feature & X86_SSE4_2)) {
252 		return (B_FALSE);
253 	} else {
254 #else
255 	{
256 		uint_t	ui = 0;
257 
258 		(void) getisax(&ui, 1);
259 
260 		if (!(ui & AV_386_SSE4_2)) {
261 			return (B_FALSE);
262 		}
263 #endif /* _KERNEL */
264 		for (i = 0; i < 256; i++) {
265 			if (crc32_table[i] != _intel_crc32_hd_table[i])
266 				return (B_FALSE);
267 		}
268 		return (B_TRUE);
269 	}
270 #else
271 	return (B_FALSE);
272 #endif
273 }
274 
275 #ifdef __cplusplus
276 }
277 #endif
278 
279 #endif /* _CRC_HD_H */
280