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