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