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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 31 /* 32 * Accelerated GHASH implementation with Intel PCLMULQDQ-NI 33 * instructions. This file contains an accelerated 34 * Galois Field Multiplication implementation. 35 * 36 * PCLMULQDQ is used to accelerate the most time-consuming part of GHASH, 37 * carry-less multiplication. More information about PCLMULQDQ can be 38 * found at: 39 * http://software.intel.com/en-us/articles/ 40 * carry-less-multiplication-and-its-usage-for-computing-the-gcm-mode/ 41 * 42 */ 43 44 /* 45 * ==================================================================== 46 * OpenSolaris OS modifications 47 * 48 * This source originates as file galois_hash_asm.c from 49 * Intel Corporation dated September 21, 2009. 50 * 51 * This OpenSolaris version has these major changes from the original source: 52 * 53 * 1. Added OpenSolaris ENTRY_NP/SET_SIZE macros from 54 * /usr/include/sys/asm_linkage.h, lint(1B) guards, and a dummy C function 55 * definition for lint. 56 * 57 * 2. Formatted code, added comments, and added #includes and #defines. 58 * 59 * 3. If bit CR0.TS is set, clear and set the TS bit, after and before 60 * calling kpreempt_disable() and kpreempt_enable(). 61 * If the TS bit is not set, Save and restore %xmm registers at the beginning 62 * and end of function calls (%xmm* registers are not saved and restored by 63 * during kernel thread preemption). 64 * 65 * 4. Removed code to perform hashing. This is already done with C macro 66 * GHASH in gcm.c. For better performance, this removed code should be 67 * reintegrated in the future to replace the C GHASH macro. 68 * 69 * 5. Added code to byte swap 16-byte input and output. 70 * 71 * 6. Folded in comments from the original C source with embedded assembly 72 * (SB_w_shift_xor.c) 73 * 74 * 7. Renamed function and reordered parameters to match OpenSolaris: 75 * Intel interface: 76 * void galois_hash_asm(unsigned char *hk, unsigned char *s, 77 * unsigned char *d, int length) 78 * OpenSolaris OS interface: 79 * void gcm_mul_pclmulqdq(uint64_t *x_in, uint64_t *y, uint64_t *res); 80 * ==================================================================== 81 */ 82 83 84 #if defined(lint) || defined(__lint) 85 86 #include <sys/types.h> 87 88 /* ARGSUSED */ 89 void 90 gcm_mul_pclmulqdq(uint64_t *x_in, uint64_t *y, uint64_t *res) { 91 } 92 93 #else /* lint */ 94 95 #include <sys/asm_linkage.h> 96 #include <sys/controlregs.h> 97 #ifdef _KERNEL 98 #include <sys/machprivregs.h> 99 #endif 100 101 #ifdef _KERNEL 102 /* 103 * Note: the CLTS macro clobbers P2 (%rsi) under i86xpv. That is, 104 * it calls HYPERVISOR_fpu_taskswitch() which modifies %rsi when it 105 * uses it to pass P2 to syscall. 106 * This also occurs with the STTS macro, but we don't care if 107 * P2 (%rsi) is modified just before function exit. 108 * The CLTS and STTS macros push and pop P1 (%rdi) already. 109 */ 110 #ifdef __xpv 111 #define PROTECTED_CLTS \ 112 push %rsi; \ 113 CLTS; \ 114 pop %rsi 115 #else 116 #define PROTECTED_CLTS \ 117 CLTS 118 #endif /* __xpv */ 119 120 /* 121 * If CR0_TS is not set, align stack (with push %rbp) and push 122 * %xmm0 - %xmm10 on stack, otherwise clear CR0_TS 123 */ 124 #define CLEAR_TS_OR_PUSH_XMM_REGISTERS(tmpreg) \ 125 push %rbp; \ 126 mov %rsp, %rbp; \ 127 movq %cr0, tmpreg; \ 128 testq $CR0_TS, tmpreg; \ 129 jnz 1f; \ 130 and $-XMM_ALIGN, %rsp; \ 131 sub $[XMM_SIZE * 11], %rsp; \ 132 movaps %xmm0, 160(%rsp); \ 133 movaps %xmm1, 144(%rsp); \ 134 movaps %xmm2, 128(%rsp); \ 135 movaps %xmm3, 112(%rsp); \ 136 movaps %xmm4, 96(%rsp); \ 137 movaps %xmm5, 80(%rsp); \ 138 movaps %xmm6, 64(%rsp); \ 139 movaps %xmm7, 48(%rsp); \ 140 movaps %xmm8, 32(%rsp); \ 141 movaps %xmm9, 16(%rsp); \ 142 movaps %xmm10, (%rsp); \ 143 jmp 2f; \ 144 1: \ 145 PROTECTED_CLTS; \ 146 2: 147 148 149 /* 150 * If CR0_TS was not set above, pop %xmm0 - %xmm10 off stack, 151 * otherwise set CR0_TS. 152 */ 153 #define SET_TS_OR_POP_XMM_REGISTERS(tmpreg) \ 154 testq $CR0_TS, tmpreg; \ 155 jnz 1f; \ 156 movaps (%rsp), %xmm10; \ 157 movaps 16(%rsp), %xmm9; \ 158 movaps 32(%rsp), %xmm8; \ 159 movaps 48(%rsp), %xmm7; \ 160 movaps 64(%rsp), %xmm6; \ 161 movaps 80(%rsp), %xmm5; \ 162 movaps 96(%rsp), %xmm4; \ 163 movaps 112(%rsp), %xmm3; \ 164 movaps 128(%rsp), %xmm2; \ 165 movaps 144(%rsp), %xmm1; \ 166 movaps 160(%rsp), %xmm0; \ 167 jmp 2f; \ 168 1: \ 169 STTS(tmpreg); \ 170 2: \ 171 mov %rbp, %rsp; \ 172 pop %rbp 173 174 175 #else 176 #define PROTECTED_CLTS 177 #define CLEAR_TS_OR_PUSH_XMM_REGISTERS(tmpreg) 178 #define SET_TS_OR_POP_XMM_REGISTERS(tmpreg) 179 #endif /* _KERNEL */ 180 181 /* 182 * Use this mask to byte-swap a 16-byte integer with the pshufb instruction 183 */ 184 185 // static uint8_t byte_swap16_mask[] = { 186 // 15, 14, 13, 12, 11, 10, 9, 8, 7, 6 ,5, 4, 3, 2, 1, 0 }; 187 .text 188 .align XMM_ALIGN 189 .Lbyte_swap16_mask: 190 .byte 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 191 192 193 194 /* 195 * void gcm_mul_pclmulqdq(uint64_t *x_in, uint64_t *y, uint64_t *res); 196 * 197 * Perform a carry-less multiplication (that is, use XOR instead of the 198 * multiply operator) on P1 and P2 and place the result in P3. 199 * 200 * Byte swap the input and the output. 201 * 202 * Note: x_in, y, and res all point to a block of 20-byte numbers 203 * (an array of two 64-bit integers). 204 * 205 * Note2: For kernel code, caller is responsible for ensuring 206 * kpreempt_disable() has been called. This is because %xmm registers are 207 * not saved/restored. Clear and set the CR0.TS bit on entry and exit, 208 * respectively, if TS is set on entry. Otherwise, if TS is not set, 209 * save and restore %xmm registers on the stack. 210 * 211 * Note3: Original Intel definition: 212 * void galois_hash_asm(unsigned char *hk, unsigned char *s, 213 * unsigned char *d, int length) 214 * 215 * Note4: Register/parameter mapping: 216 * Intel: 217 * Parameter 1: %rcx (copied to %xmm0) hk or x_in 218 * Parameter 2: %rdx (copied to %xmm1) s or y 219 * Parameter 3: %rdi (result) d or res 220 * OpenSolaris: 221 * Parameter 1: %rdi (copied to %xmm0) x_in 222 * Parameter 2: %rsi (copied to %xmm1) y 223 * Parameter 3: %rdx (result) res 224 */ 225 226 ENTRY_NP(gcm_mul_pclmulqdq) 227 CLEAR_TS_OR_PUSH_XMM_REGISTERS(%r10) 228 229 // 230 // Copy Parameters 231 // 232 movdqu (%rdi), %xmm0 // P1 233 movdqu (%rsi), %xmm1 // P2 234 235 // 236 // Byte swap 16-byte input 237 // 238 lea .Lbyte_swap16_mask(%rip), %rax 239 movaps (%rax), %xmm10 240 pshufb %xmm10, %xmm0 241 pshufb %xmm10, %xmm1 242 243 244 // 245 // Multiply with the hash key 246 // 247 movdqu %xmm0, %xmm3 248 pclmulqdq $0, %xmm1, %xmm3 // xmm3 holds a0*b0 249 250 movdqu %xmm0, %xmm4 251 pclmulqdq $16, %xmm1, %xmm4 // xmm4 holds a0*b1 252 253 movdqu %xmm0, %xmm5 254 pclmulqdq $1, %xmm1, %xmm5 // xmm5 holds a1*b0 255 movdqu %xmm0, %xmm6 256 pclmulqdq $17, %xmm1, %xmm6 // xmm6 holds a1*b1 257 258 pxor %xmm5, %xmm4 // xmm4 holds a0*b1 + a1*b0 259 260 movdqu %xmm4, %xmm5 // move the contents of xmm4 to xmm5 261 psrldq $8, %xmm4 // shift by xmm4 64 bits to the right 262 pslldq $8, %xmm5 // shift by xmm5 64 bits to the left 263 pxor %xmm5, %xmm3 264 pxor %xmm4, %xmm6 // Register pair <xmm6:xmm3> holds the result 265 // of the carry-less multiplication of 266 // xmm0 by xmm1. 267 268 // We shift the result of the multiplication by one bit position 269 // to the left to cope for the fact that the bits are reversed. 270 movdqu %xmm3, %xmm7 271 movdqu %xmm6, %xmm8 272 pslld $1, %xmm3 273 pslld $1, %xmm6 274 psrld $31, %xmm7 275 psrld $31, %xmm8 276 movdqu %xmm7, %xmm9 277 pslldq $4, %xmm8 278 pslldq $4, %xmm7 279 psrldq $12, %xmm9 280 por %xmm7, %xmm3 281 por %xmm8, %xmm6 282 por %xmm9, %xmm6 283 284 // 285 // First phase of the reduction 286 // 287 // Move xmm3 into xmm7, xmm8, xmm9 in order to perform the shifts 288 // independently. 289 movdqu %xmm3, %xmm7 290 movdqu %xmm3, %xmm8 291 movdqu %xmm3, %xmm9 292 pslld $31, %xmm7 // packed right shift shifting << 31 293 pslld $30, %xmm8 // packed right shift shifting << 30 294 pslld $25, %xmm9 // packed right shift shifting << 25 295 pxor %xmm8, %xmm7 // xor the shifted versions 296 pxor %xmm9, %xmm7 297 movdqu %xmm7, %xmm8 298 pslldq $12, %xmm7 299 psrldq $4, %xmm8 300 pxor %xmm7, %xmm3 // first phase of the reduction complete 301 302 // 303 // Second phase of the reduction 304 // 305 // Make 3 copies of xmm3 in xmm2, xmm4, xmm5 for doing these 306 // shift operations. 307 movdqu %xmm3, %xmm2 308 movdqu %xmm3, %xmm4 // packed left shifting >> 1 309 movdqu %xmm3, %xmm5 310 psrld $1, %xmm2 311 psrld $2, %xmm4 // packed left shifting >> 2 312 psrld $7, %xmm5 // packed left shifting >> 7 313 pxor %xmm4, %xmm2 // xor the shifted versions 314 pxor %xmm5, %xmm2 315 pxor %xmm8, %xmm2 316 pxor %xmm2, %xmm3 317 pxor %xmm3, %xmm6 // the result is in xmm6 318 319 // 320 // Byte swap 16-byte result 321 // 322 pshufb %xmm10, %xmm6 // %xmm10 has the swap mask 323 324 // 325 // Store the result 326 // 327 movdqu %xmm6, (%rdx) // P3 328 329 330 // 331 // Cleanup and Return 332 // 333 SET_TS_OR_POP_XMM_REGISTERS(%r10) 334 ret 335 SET_SIZE(gcm_mul_pclmulqdq) 336 337 #endif /* lint || __lint */