hd_crc.h revision 11287:81483c8a0a88
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
36extern "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
63static INLINE uint32_t
64#ifdef _KERNEL
65/*LINTED:E_FUNC_ARG_UNUSED*/
66mm_crc32_u8(uint32_t crc, uint8_t *data)
67#else
68mm_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
82static INLINE uint32_t
83#ifdef _KERNEL
84/*LINTED:E_FUNC_ARG_UNUSED*/
85mm_crc32_u64(uint32_t crc, uint64_t *data)
86#else
87mm_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
106static INLINE uint32_t
107#ifdef _KERNEL
108/*LINTED:E_FUNC_ARG_UNUSED*/
109mm_crc32_u32(uint32_t crc, uint32_t *data)
110#else
111mm_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
130static INLINE uint32_t
131intel_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
171static INLINE boolean_t
172#if defined(_KERNEL) && !defined(__i386) && !defined(__amd_64) &&\
173	!defined(__x86_64)
174/*LINTED:E_FUNC_ARG_UNUSED*/
175hd_crc32_avail(uint32_t *crc32_table)
176#else
177hd_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