| /* | |
| * Copyright (c) 2019, 2024, Intel Corporation. All rights reserved. | |
| * | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| * | |
| */ | |
| #include "asm/assembler.hpp" | |
| #include "asm/assembler.inline.hpp" | |
| #include "runtime/stubRoutines.hpp" | |
| #include "macroAssembler_x86.hpp" | |
| #include "stubGenerator_x86_64.hpp" | |
| #define __ _masm-> | |
| #ifdef PRODUCT | |
| #define BLOCK_COMMENT(str) /* nothing */ | |
| #else | |
| #define BLOCK_COMMENT(str) __ block_comment(str) | |
| #endif // PRODUCT | |
| #define BIND(label) bind(label); BLOCK_COMMENT(#label ":") | |
| // Constants | |
| const int AESBlockSize = 16; | |
| // Shuffle mask for fixing up 128-bit words consisting of big-endian 32-bit integers. | |
| ATTRIBUTE_ALIGNED(16) static const uint64_t KEY_SHUFFLE_MASK[] = { | |
| 0x0405060700010203UL, 0x0C0D0E0F08090A0BUL | |
| }; | |
| static address key_shuffle_mask_addr() { | |
| return (address)KEY_SHUFFLE_MASK; | |
| } | |
| // Shuffle mask for big-endian 128-bit integers. | |
| ATTRIBUTE_ALIGNED(64) static const uint64_t COUNTER_SHUFFLE_MASK[] = { | |
| 0x08090A0B0C0D0E0FUL, 0x0001020304050607UL, | |
| 0x08090A0B0C0D0E0FUL, 0x0001020304050607UL, | |
| 0x08090A0B0C0D0E0FUL, 0x0001020304050607UL, | |
| 0x08090A0B0C0D0E0FUL, 0x0001020304050607UL, | |
| }; | |
| static address counter_shuffle_mask_addr() { | |
| return (address)COUNTER_SHUFFLE_MASK; | |
| } | |
| // This mask is used for incrementing counter value | |
| ATTRIBUTE_ALIGNED(64) static const uint64_t COUNTER_MASK_LINC0[] = { | |
| 0x0000000000000000UL, 0x0000000000000000UL, | |
| 0x0000000000000001UL, 0x0000000000000000UL, | |
| 0x0000000000000002UL, 0x0000000000000000UL, | |
| 0x0000000000000003UL, 0x0000000000000000UL, | |
| }; | |
| static address counter_mask_linc0_addr() { | |
| return (address)COUNTER_MASK_LINC0; | |
| } | |
| ATTRIBUTE_ALIGNED(16) static const uint64_t COUNTER_MASK_LINC1[] = { | |
| 0x0000000000000001UL, 0x0000000000000000UL, | |
| }; | |
| static address counter_mask_linc1_addr() { | |
| return (address)COUNTER_MASK_LINC1; | |
| } | |
| ATTRIBUTE_ALIGNED(16) uint64_t COUNTER_MASK_LINC1F[] = { | |
| 0x0000000000000000UL, 0x0100000000000000UL, | |
| }; | |
| static address counter_mask_linc1f_addr() { | |
| return (address)COUNTER_MASK_LINC1F; | |
| } | |
| ATTRIBUTE_ALIGNED(16) uint64_t COUNTER_MASK_LINC2[] = { | |
| 0x0000000000000002UL, 0x0000000000000000UL, | |
| }; | |
| static address counter_mask_linc2_addr() { | |
| return (address)COUNTER_MASK_LINC2; | |
| } | |
| ATTRIBUTE_ALIGNED(16) uint64_t COUNTER_MASK_LINC2F[] = { | |
| 0x0000000000000000UL, 0x0200000000000000UL, | |
| }; | |
| static address counter_mask_linc2f_addr() { | |
| return (address)COUNTER_MASK_LINC2F; | |
| } | |
| ATTRIBUTE_ALIGNED(64) static const uint64_t COUNTER_MASK_LINC4[] = { | |
| 0x0000000000000004UL, 0x0000000000000000UL, | |
| 0x0000000000000004UL, 0x0000000000000000UL, | |
| 0x0000000000000004UL, 0x0000000000000000UL, | |
| 0x0000000000000004UL, 0x0000000000000000UL, | |
| }; | |
| static address counter_mask_linc4_addr() { | |
| return (address)COUNTER_MASK_LINC4; | |
| } | |
| ATTRIBUTE_ALIGNED(64) static const uint64_t COUNTER_MASK_LINC8[] = { | |
| 0x0000000000000008UL, 0x0000000000000000UL, | |
| 0x0000000000000008UL, 0x0000000000000000UL, | |
| 0x0000000000000008UL, 0x0000000000000000UL, | |
| 0x0000000000000008UL, 0x0000000000000000UL, | |
| }; | |
| static address counter_mask_linc8_addr() { | |
| return (address)COUNTER_MASK_LINC8; | |
| } | |
| ATTRIBUTE_ALIGNED(64) static const uint64_t COUNTER_MASK_LINC16[] = { | |
| 0x0000000000000010UL, 0x0000000000000000UL, | |
| 0x0000000000000010UL, 0x0000000000000000UL, | |
| 0x0000000000000010UL, 0x0000000000000000UL, | |
| 0x0000000000000010UL, 0x0000000000000000UL, | |
| }; | |
| static address counter_mask_linc16_addr() { | |
| return (address)COUNTER_MASK_LINC16; | |
| } | |
| ATTRIBUTE_ALIGNED(64) static const uint64_t COUNTER_MASK_LINC32[] = { | |
| 0x0000000000000020UL, 0x0000000000000000UL, | |
| 0x0000000000000020UL, 0x0000000000000000UL, | |
| 0x0000000000000020UL, 0x0000000000000000UL, | |
| 0x0000000000000020UL, 0x0000000000000000UL, | |
| }; | |
| static address counter_mask_linc32_addr() { | |
| return (address)COUNTER_MASK_LINC32; | |
| } | |
| ATTRIBUTE_ALIGNED(64) uint64_t COUNTER_MASK_ONES[] = { | |
| 0x0000000000000000UL, 0x0000000000000001UL, | |
| 0x0000000000000000UL, 0x0000000000000001UL, | |
| 0x0000000000000000UL, 0x0000000000000001UL, | |
| 0x0000000000000000UL, 0x0000000000000001UL, | |
| }; | |
| static address counter_mask_ones_addr() { | |
| return (address)COUNTER_MASK_ONES; | |
| } | |
| ATTRIBUTE_ALIGNED(64) static const uint64_t GHASH_POLYNOMIAL_REDUCTION[] = { | |
| 0x00000001C2000000UL, 0xC200000000000000UL, | |
| 0x00000001C2000000UL, 0xC200000000000000UL, | |
| 0x00000001C2000000UL, 0xC200000000000000UL, | |
| 0x00000001C2000000UL, 0xC200000000000000UL, | |
| }; | |
| static address ghash_polynomial_reduction_addr() { | |
| return (address)GHASH_POLYNOMIAL_REDUCTION; | |
| } | |
| ATTRIBUTE_ALIGNED(16) static const uint64_t GHASH_POLYNOMIAL_TWO_ONE[] = { | |
| 0x0000000000000001UL, 0x0000000100000000UL, | |
| }; | |
| static address ghash_polynomial_two_one_addr() { | |
| return (address)GHASH_POLYNOMIAL_TWO_ONE; | |
| } | |
| // This mask is used for incrementing counter value | |
| ATTRIBUTE_ALIGNED(64) static const uint64_t COUNTER_MASK_ADDBE_4444[] = { | |
| 0x0000000000000000ULL, 0x0400000000000000ULL, | |
| 0x0000000000000000ULL, 0x0400000000000000ULL, | |
| 0x0000000000000000ULL, 0x0400000000000000ULL, | |
| 0x0000000000000000ULL, 0x0400000000000000ULL, | |
| }; | |
| static address counter_mask_addbe_4444_addr() { | |
| return (address)COUNTER_MASK_ADDBE_4444; | |
| } | |
| // This mask is used for incrementing counter value | |
| ATTRIBUTE_ALIGNED(64) static const uint64_t COUNTER_MASK_ADDBE_1234[] = { | |
| 0x0000000000000000ULL, 0x0100000000000000ULL, | |
| 0x0000000000000000ULL, 0x0200000000000000ULL, | |
| 0x0000000000000000ULL, 0x0300000000000000ULL, | |
| 0x0000000000000000ULL, 0x0400000000000000ULL, | |
| }; | |
| static address counter_mask_addbe_1234_addr() { | |
| return (address)COUNTER_MASK_ADDBE_1234; | |
| } | |
| // This mask is used for incrementing counter value | |
| ATTRIBUTE_ALIGNED(64) static const uint64_t COUNTER_MASK_ADD_1234[] = { | |
| 0x0000000000000001ULL, 0x0000000000000000ULL, | |
| 0x0000000000000002ULL, 0x0000000000000000ULL, | |
| 0x0000000000000003ULL, 0x0000000000000000ULL, | |
| 0x0000000000000004ULL, 0x0000000000000000ULL, | |
| }; | |
| static address counter_mask_add_1234_addr() { | |
| return (address)COUNTER_MASK_ADD_1234; | |
| } | |
| // AES intrinsic stubs | |
| void StubGenerator::generate_aes_stubs() { | |
| if (UseAESIntrinsics) { | |
| StubRoutines::_aescrypt_encryptBlock = generate_aescrypt_encryptBlock(); | |
| StubRoutines::_aescrypt_decryptBlock = generate_aescrypt_decryptBlock(); | |
| StubRoutines::_cipherBlockChaining_encryptAESCrypt = generate_cipherBlockChaining_encryptAESCrypt(); | |
| if (VM_Version::supports_avx512_vaes() && VM_Version::supports_avx512vl() && VM_Version::supports_avx512dq() ) { | |
| StubRoutines::_cipherBlockChaining_decryptAESCrypt = generate_cipherBlockChaining_decryptVectorAESCrypt(); | |
| StubRoutines::_electronicCodeBook_encryptAESCrypt = generate_electronicCodeBook_encryptAESCrypt(); | |
| StubRoutines::_electronicCodeBook_decryptAESCrypt = generate_electronicCodeBook_decryptAESCrypt(); | |
| StubRoutines::_galoisCounterMode_AESCrypt = generate_galoisCounterMode_AESCrypt(); | |
| } else { | |
| StubRoutines::_cipherBlockChaining_decryptAESCrypt = generate_cipherBlockChaining_decryptAESCrypt_Parallel(); | |
| if (VM_Version::supports_avx2()) { | |
| StubRoutines::_galoisCounterMode_AESCrypt = generate_avx2_galoisCounterMode_AESCrypt(); | |
| } | |
| } | |
| } | |
| if (UseAESCTRIntrinsics) { | |
| if (VM_Version::supports_avx512_vaes() && VM_Version::supports_avx512bw() && VM_Version::supports_avx512vl()) { | |
| StubRoutines::_counterMode_AESCrypt = generate_counterMode_VectorAESCrypt(); | |
| } else { | |
| StubRoutines::_counterMode_AESCrypt = generate_counterMode_AESCrypt_Parallel(); | |
| } | |
| } | |
| } | |
| // Vector AES Galois Counter Mode implementation. | |
| // | |
| // Inputs: Windows | Linux | |
| // in = rcx (c_rarg0) | rsi (c_rarg0) | |
| // len = rdx (c_rarg1) | rdi (c_rarg1) | |
| // ct = r8 (c_rarg2) | rdx (c_rarg2) | |
| // out = r9 (c_rarg3) | rcx (c_rarg3) | |
| // key = rsi | r8 (c_rarg4) | |
| // state = rdi | r9 (c_rarg5) | |
| // subkeyHtbl = r10 | r10 | |
| // counter = r11 | r11 | |
| // | |
| // Output: | |
| // rax - number of processed bytes | |
| address StubGenerator::generate_galoisCounterMode_AESCrypt() { | |
| __ align(CodeEntryAlignment); | |
| StubGenStubId stub_id = StubGenStubId::galoisCounterMode_AESCrypt_id; | |
| StubCodeMark mark(this, stub_id); | |
| address start = __ pc(); | |
| const Register in = c_rarg0; | |
| const Register len = c_rarg1; | |
| const Register ct = c_rarg2; | |
| const Register out = c_rarg3; | |
| // and updated with the incremented counter in the end | |
| #ifndef _WIN64 | |
| const Register key = c_rarg4; | |
| const Register state = c_rarg5; | |
| const Address subkeyH_mem(rbp, 2 * wordSize); | |
| const Register subkeyHtbl = r10; | |
| const Register avx512_subkeyHtbl = r12; | |
| const Address counter_mem(rbp, 3 * wordSize); | |
| const Register counter = r11; | |
| #else | |
| const Address key_mem(rbp, 6 * wordSize); | |
| const Register key = rsi; | |
| const Address state_mem(rbp, 7 * wordSize); | |
| const Register state = rdi; | |
| const Address subkeyH_mem(rbp, 8 * wordSize); | |
| const Register subkeyHtbl = r10; | |
| const Register avx512_subkeyHtbl = r12; | |
| const Address counter_mem(rbp, 9 * wordSize); | |
| const Register counter = r11; | |
| #endif | |
| __ enter(); | |
| // Save state before entering routine | |
| __ push(r12);//holds pointer to avx512_subkeyHtbl | |
| __ push(r14);//holds CTR_CHECK value to check for overflow | |
| __ push(r15);//holds number of rounds | |
| __ push(rbx);//scratch register | |
| #ifdef _WIN64 | |
| // on win64, fill len_reg from stack position | |
| __ push(rsi); | |
| __ push(rdi); | |
| __ movptr(key, key_mem); | |
| __ movptr(state, state_mem); | |
| #endif | |
| __ movptr(subkeyHtbl, subkeyH_mem); | |
| __ movptr(counter, counter_mem); | |
| // Align stack | |
| __ andq(rsp, -64); | |
| __ subptr(rsp, 200 * longSize); // Create space on the stack for 64 htbl entries and 8 zmm AES entries | |
| __ movptr(avx512_subkeyHtbl, rsp); | |
| aesgcm_avx512(in, len, ct, out, key, state, subkeyHtbl, avx512_subkeyHtbl, counter); | |
| __ vzeroupper(); | |
| // Restore state before leaving routine | |
| #ifdef _WIN64 | |
| __ lea(rsp, Address(rbp, -6 * wordSize)); | |
| __ pop(rdi); | |
| __ pop(rsi); | |
| #else | |
| __ lea(rsp, Address(rbp, -4 * wordSize)); | |
| #endif | |
| __ pop(rbx); | |
| __ pop(r15); | |
| __ pop(r14); | |
| __ pop(r12); | |
| __ leave(); // required for proper stackwalking of RuntimeStub frame | |
| __ ret(0); | |
| return start; | |
| } | |
| // AVX2 Vector AES Galois Counter Mode implementation. | |
| // | |
| // Inputs: Windows | Linux | |
| // in = rcx (c_rarg0) | rsi (c_rarg0) | |
| // len = rdx (c_rarg1) | rdi (c_rarg1) | |
| // ct = r8 (c_rarg2) | rdx (c_rarg2) | |
| // out = r9 (c_rarg3) | rcx (c_rarg3) | |
| // key = rdi | r8 (c_rarg4) | |
| // state = r13 | r9 (c_rarg5) | |
| // subkeyHtbl = r11 | r11 | |
| // counter = rsi | r12 | |
| // | |
| // Output: | |
| // rax - number of processed bytes | |
| address StubGenerator::generate_avx2_galoisCounterMode_AESCrypt() { | |
| __ align(CodeEntryAlignment); | |
| StubGenStubId stub_id = StubGenStubId::galoisCounterMode_AESCrypt_id; | |
| StubCodeMark mark(this, stub_id); | |
| address start = __ pc(); | |
| const Register in = c_rarg0; | |
| const Register len = c_rarg1; | |
| const Register ct = c_rarg2; | |
| const Register out = c_rarg3; | |
| // and updated with the incremented counter in the end | |
| #ifndef _WIN64 | |
| const Register key = c_rarg4; | |
| const Register state = c_rarg5; | |
| const Address subkeyH_mem(rbp, 2 * wordSize); | |
| const Register subkeyHtbl = r11; | |
| const Address counter_mem(rbp, 3 * wordSize); | |
| const Register counter = r12; | |
| #else | |
| const Address key_mem(rbp, 6 * wordSize); | |
| const Register key = rdi; | |
| const Address state_mem(rbp, 7 * wordSize); | |
| const Register state = r13; | |
| const Address subkeyH_mem(rbp, 8 * wordSize); | |
| const Register subkeyHtbl = r11; | |
| const Address counter_mem(rbp, 9 * wordSize); | |
| const Register counter = rsi; | |
| #endif | |
| __ enter(); | |
| // Save state before entering routine | |
| __ push(r12); | |
| __ push(r13); | |
| __ push(r14); | |
| __ push(r15); | |
| __ push(rbx); | |
| #ifdef _WIN64 | |
| // on win64, fill len_reg from stack position | |
| __ push(rsi); | |
| __ push(rdi); | |
| __ movptr(key, key_mem); | |
| __ movptr(state, state_mem); | |
| #endif | |
| __ movptr(subkeyHtbl, subkeyH_mem); | |
| __ movptr(counter, counter_mem); | |
| // Save rsp | |
| __ movq(r14, rsp); | |
| // Align stack | |
| __ andq(rsp, -64); | |
| __ subptr(rsp, 16 * longSize); // Create space on the stack for saving AES entries | |
| aesgcm_avx2(in, len, ct, out, key, state, subkeyHtbl, counter); | |
| __ vzeroupper(); | |
| __ movq(rsp, r14); | |
| // Restore state before leaving routine | |
| #ifdef _WIN64 | |
| __ pop(rdi); | |
| __ pop(rsi); | |
| #endif | |
| __ pop(rbx); | |
| __ pop(r15); | |
| __ pop(r14); | |
| __ pop(r13); | |
| __ pop(r12); | |
| __ leave(); // required for proper stackwalking of RuntimeStub frame | |
| __ ret(0); | |
| return start; | |
| } | |
| // Vector AES Counter implementation | |
| address StubGenerator::generate_counterMode_VectorAESCrypt() { | |
| __ align(CodeEntryAlignment); | |
| StubGenStubId stub_id = StubGenStubId::counterMode_AESCrypt_id; | |
| StubCodeMark mark(this, stub_id); | |
| address start = __ pc(); | |
| const Register from = c_rarg0; // source array address | |
| const Register to = c_rarg1; // destination array address | |
| const Register key = c_rarg2; // key array address r8 | |
| const Register counter = c_rarg3; // counter byte array initialized from counter array address | |
| // and updated with the incremented counter in the end | |
| #ifndef _WIN64 | |
| const Register len_reg = c_rarg4; | |
| const Register saved_encCounter_start = c_rarg5; | |
| const Register used_addr = r10; | |
| const Address used_mem(rbp, 2 * wordSize); | |
| const Register used = r11; | |
| #else | |
| const Address len_mem(rbp, 6 * wordSize); // length is on stack on Win64 | |
| const Address saved_encCounter_mem(rbp, 7 * wordSize); // saved encrypted counter is on stack on Win64 | |
| const Address used_mem(rbp, 8 * wordSize); // used length is on stack on Win64 | |
| const Register len_reg = r10; // pick the first volatile windows register | |
| const Register saved_encCounter_start = r11; | |
| const Register used_addr = r13; | |
| const Register used = r14; | |
| #endif | |
| __ enter(); | |
| // Save state before entering routine | |
| __ push(r12); | |
| __ push(r13); | |
| __ push(r14); | |
| __ push(r15); | |
| #ifdef _WIN64 | |
| // on win64, fill len_reg from stack position | |
| __ movl(len_reg, len_mem); | |
| __ movptr(saved_encCounter_start, saved_encCounter_mem); | |
| __ movptr(used_addr, used_mem); | |
| __ movl(used, Address(used_addr, 0)); | |
| #else | |
| __ push(len_reg); // Save | |
| __ movptr(used_addr, used_mem); | |
| __ movl(used, Address(used_addr, 0)); | |
| #endif | |
| __ push(rbx); | |
| aesctr_encrypt(from, to, key, counter, len_reg, used, used_addr, saved_encCounter_start); | |
| __ vzeroupper(); | |
| // Restore state before leaving routine | |
| __ pop(rbx); | |
| #ifdef _WIN64 | |
| __ movl(rax, len_mem); // return length | |
| #else | |
| __ pop(rax); // return length | |
| #endif | |
| __ pop(r15); | |
| __ pop(r14); | |
| __ pop(r13); | |
| __ pop(r12); | |
| __ leave(); // required for proper stackwalking of RuntimeStub frame | |
| __ ret(0); | |
| return start; | |
| } | |
| // This is a version of CTR/AES crypt which does 6 blocks in a loop at a time | |
| // to hide instruction latency | |
| // | |
| // Arguments: | |
| // | |
| // Inputs: | |
| // c_rarg0 - source byte array address | |
| // c_rarg1 - destination byte array address | |
| // c_rarg2 - K (key) in little endian int array | |
| // c_rarg3 - counter vector byte array address | |
| // Linux | |
| // c_rarg4 - input length | |
| // c_rarg5 - saved encryptedCounter start | |
| // rbp + 6 * wordSize - saved used length | |
| // Windows | |
| // rbp + 6 * wordSize - input length | |
| // rbp + 7 * wordSize - saved encryptedCounter start | |
| // rbp + 8 * wordSize - saved used length | |
| // | |
| // Output: | |
| // rax - input length | |
| // | |
| address StubGenerator::generate_counterMode_AESCrypt_Parallel() { | |
| assert(UseAES, "need AES instructions and misaligned SSE support"); | |
| __ align(CodeEntryAlignment); | |
| StubGenStubId stub_id = StubGenStubId::counterMode_AESCrypt_id; | |
| StubCodeMark mark(this, stub_id); | |
| address start = __ pc(); | |
| const Register from = c_rarg0; // source array address | |
| const Register to = c_rarg1; // destination array address | |
| const Register key = c_rarg2; // key array address | |
| const Register counter = c_rarg3; // counter byte array initialized from counter array address | |
| // and updated with the incremented counter in the end | |
| #ifndef _WIN64 | |
| const Register len_reg = c_rarg4; | |
| const Register saved_encCounter_start = c_rarg5; | |
| const Register used_addr = r10; | |
| const Address used_mem(rbp, 2 * wordSize); | |
| const Register used = r11; | |
| #else | |
| const Address len_mem(rbp, 6 * wordSize); // length is on stack on Win64 | |
| const Address saved_encCounter_mem(rbp, 7 * wordSize); // length is on stack on Win64 | |
| const Address used_mem(rbp, 8 * wordSize); // length is on stack on Win64 | |
| const Register len_reg = r10; // pick the first volatile windows register | |
| const Register saved_encCounter_start = r11; | |
| const Register used_addr = r13; | |
| const Register used = r14; | |
| #endif | |
| const Register pos = rax; | |
| const int PARALLEL_FACTOR = 6; | |
| const XMMRegister xmm_counter_shuf_mask = xmm0; | |
| const XMMRegister xmm_key_shuf_mask = xmm1; // used temporarily to swap key bytes up front | |
| const XMMRegister xmm_curr_counter = xmm2; | |
| const XMMRegister xmm_key_tmp0 = xmm3; | |
| const XMMRegister xmm_key_tmp1 = xmm4; | |
| // registers holding the four results in the parallelized loop | |
| const XMMRegister xmm_result0 = xmm5; | |
| const XMMRegister xmm_result1 = xmm6; | |
| const XMMRegister xmm_result2 = xmm7; | |
| const XMMRegister xmm_result3 = xmm8; | |
| const XMMRegister xmm_result4 = xmm9; | |
| const XMMRegister xmm_result5 = xmm10; | |
| const XMMRegister xmm_from0 = xmm11; | |
| const XMMRegister xmm_from1 = xmm12; | |
| const XMMRegister xmm_from2 = xmm13; | |
| const XMMRegister xmm_from3 = xmm14; //the last one is xmm14. we have to preserve it on WIN64. | |
| const XMMRegister xmm_from4 = xmm3; //reuse xmm3~4. Because xmm_key_tmp0~1 are useless when loading input text | |
| const XMMRegister xmm_from5 = xmm4; | |
| //for key_128, key_192, key_256 | |
| const int rounds[3] = {10, 12, 14}; | |
| Label L_exit_preLoop, L_preLoop_start; | |
| Label L_multiBlock_loopTop[3]; | |
| Label L_singleBlockLoopTop[3]; | |
| Label L__incCounter[3][6]; //for 6 blocks | |
| Label L__incCounter_single[3]; //for single block, key128, key192, key256 | |
| Label L_processTail_insr[3], L_processTail_4_insr[3], L_processTail_2_insr[3], L_processTail_1_insr[3], L_processTail_exit_insr[3]; | |
| Label L_processTail_4_extr[3], L_processTail_2_extr[3], L_processTail_1_extr[3], L_processTail_exit_extr[3]; | |
| Label L_exit; | |
| __ enter(); // required for proper stackwalking of RuntimeStub frame | |
| #ifdef _WIN64 | |
| // allocate spill slots for r13, r14 | |
| enum { | |
| saved_r13_offset, | |
| saved_r14_offset | |
| }; | |
| __ subptr(rsp, 2 * wordSize); | |
| __ movptr(Address(rsp, saved_r13_offset * wordSize), r13); | |
| __ movptr(Address(rsp, saved_r14_offset * wordSize), r14); | |
| // on win64, fill len_reg from stack position | |
| __ movl(len_reg, len_mem); | |
| __ movptr(saved_encCounter_start, saved_encCounter_mem); | |
| __ movptr(used_addr, used_mem); | |
| __ movl(used, Address(used_addr, 0)); | |
| #else | |
| __ push(len_reg); // Save | |
| __ movptr(used_addr, used_mem); | |
| __ movl(used, Address(used_addr, 0)); | |
| #endif | |
| __ push(rbx); // Save RBX | |
| __ movdqu(xmm_curr_counter, Address(counter, 0x00)); // initialize counter with initial counter | |
| __ movdqu(xmm_counter_shuf_mask, ExternalAddress(counter_shuffle_mask_addr()), pos /*rscratch*/); | |
| __ pshufb(xmm_curr_counter, xmm_counter_shuf_mask); //counter is shuffled | |
| __ movptr(pos, 0); | |
| // Use the partially used encrpyted counter from last invocation | |
| __ BIND(L_preLoop_start); | |
| __ cmpptr(used, 16); | |
| __ jcc(Assembler::aboveEqual, L_exit_preLoop); | |
| __ cmpptr(len_reg, 0); | |
| __ jcc(Assembler::lessEqual, L_exit_preLoop); | |
| __ movb(rbx, Address(saved_encCounter_start, used)); | |
| __ xorb(rbx, Address(from, pos)); | |
| __ movb(Address(to, pos), rbx); | |
| __ addptr(pos, 1); | |
| __ addptr(used, 1); | |
| __ subptr(len_reg, 1); | |
| __ jmp(L_preLoop_start); | |
| __ BIND(L_exit_preLoop); | |
| __ movl(Address(used_addr, 0), used); | |
| // key length could be only {11, 13, 15} * 4 = {44, 52, 60} | |
| __ movdqu(xmm_key_shuf_mask, ExternalAddress(key_shuffle_mask_addr()), rbx /*rscratch*/); | |
| __ movl(rbx, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); | |
| __ cmpl(rbx, 52); | |
| __ jcc(Assembler::equal, L_multiBlock_loopTop[1]); | |
| __ cmpl(rbx, 60); | |
| __ jcc(Assembler::equal, L_multiBlock_loopTop[2]); | |
| #define CTR_DoSix(opc, src_reg) \ | |
| __ opc(xmm_result0, src_reg); \ | |
| __ opc(xmm_result1, src_reg); \ | |
| __ opc(xmm_result2, src_reg); \ | |
| __ opc(xmm_result3, src_reg); \ | |
| __ opc(xmm_result4, src_reg); \ | |
| __ opc(xmm_result5, src_reg); | |
| // k == 0 : generate code for key_128 | |
| // k == 1 : generate code for key_192 | |
| // k == 2 : generate code for key_256 | |
| for (int k = 0; k < 3; ++k) { | |
| //multi blocks starts here | |
| __ align(OptoLoopAlignment); | |
| __ BIND(L_multiBlock_loopTop[k]); | |
| __ cmpptr(len_reg, PARALLEL_FACTOR * AESBlockSize); // see if at least PARALLEL_FACTOR blocks left | |
| __ jcc(Assembler::less, L_singleBlockLoopTop[k]); | |
| load_key(xmm_key_tmp0, key, 0x00, xmm_key_shuf_mask); | |
| //load, then increase counters | |
| CTR_DoSix(movdqa, xmm_curr_counter); | |
| inc_counter(rbx, xmm_result1, 0x01, L__incCounter[k][0]); | |
| inc_counter(rbx, xmm_result2, 0x02, L__incCounter[k][1]); | |
| inc_counter(rbx, xmm_result3, 0x03, L__incCounter[k][2]); | |
| inc_counter(rbx, xmm_result4, 0x04, L__incCounter[k][3]); | |
| inc_counter(rbx, xmm_result5, 0x05, L__incCounter[k][4]); | |
| inc_counter(rbx, xmm_curr_counter, 0x06, L__incCounter[k][5]); | |
| CTR_DoSix(pshufb, xmm_counter_shuf_mask); // after increased, shuffled counters back for PXOR | |
| CTR_DoSix(pxor, xmm_key_tmp0); //PXOR with Round 0 key | |
| //load two ROUND_KEYs at a time | |
| for (int i = 1; i < rounds[k]; ) { | |
| load_key(xmm_key_tmp1, key, (0x10 * i), xmm_key_shuf_mask); | |
| load_key(xmm_key_tmp0, key, (0x10 * (i+1)), xmm_key_shuf_mask); | |
| CTR_DoSix(aesenc, xmm_key_tmp1); | |
| i++; | |
| if (i != rounds[k]) { | |
| CTR_DoSix(aesenc, xmm_key_tmp0); | |
| } else { | |
| CTR_DoSix(aesenclast, xmm_key_tmp0); | |
| } | |
| i++; | |
| } | |
| // get next PARALLEL_FACTOR blocks into xmm_result registers | |
| __ movdqu(xmm_from0, Address(from, pos, Address::times_1, 0 * AESBlockSize)); | |
| __ movdqu(xmm_from1, Address(from, pos, Address::times_1, 1 * AESBlockSize)); | |
| __ movdqu(xmm_from2, Address(from, pos, Address::times_1, 2 * AESBlockSize)); | |
| __ movdqu(xmm_from3, Address(from, pos, Address::times_1, 3 * AESBlockSize)); | |
| __ movdqu(xmm_from4, Address(from, pos, Address::times_1, 4 * AESBlockSize)); | |
| __ movdqu(xmm_from5, Address(from, pos, Address::times_1, 5 * AESBlockSize)); | |
| __ pxor(xmm_result0, xmm_from0); | |
| __ pxor(xmm_result1, xmm_from1); | |
| __ pxor(xmm_result2, xmm_from2); | |
| __ pxor(xmm_result3, xmm_from3); | |
| __ pxor(xmm_result4, xmm_from4); | |
| __ pxor(xmm_result5, xmm_from5); | |
| // store 6 results into the next 64 bytes of output | |
| __ movdqu(Address(to, pos, Address::times_1, 0 * AESBlockSize), xmm_result0); | |
| __ movdqu(Address(to, pos, Address::times_1, 1 * AESBlockSize), xmm_result1); | |
| __ movdqu(Address(to, pos, Address::times_1, 2 * AESBlockSize), xmm_result2); | |
| __ movdqu(Address(to, pos, Address::times_1, 3 * AESBlockSize), xmm_result3); | |
| __ movdqu(Address(to, pos, Address::times_1, 4 * AESBlockSize), xmm_result4); | |
| __ movdqu(Address(to, pos, Address::times_1, 5 * AESBlockSize), xmm_result5); | |
| __ addptr(pos, PARALLEL_FACTOR * AESBlockSize); // increase the length of crypt text | |
| __ subptr(len_reg, PARALLEL_FACTOR * AESBlockSize); // decrease the remaining length | |
| __ jmp(L_multiBlock_loopTop[k]); | |
| // singleBlock starts here | |
| __ align(OptoLoopAlignment); | |
| __ BIND(L_singleBlockLoopTop[k]); | |
| __ cmpptr(len_reg, 0); | |
| __ jcc(Assembler::lessEqual, L_exit); | |
| load_key(xmm_key_tmp0, key, 0x00, xmm_key_shuf_mask); | |
| __ movdqa(xmm_result0, xmm_curr_counter); | |
| inc_counter(rbx, xmm_curr_counter, 0x01, L__incCounter_single[k]); | |
| __ pshufb(xmm_result0, xmm_counter_shuf_mask); | |
| __ pxor(xmm_result0, xmm_key_tmp0); | |
| for (int i = 1; i < rounds[k]; i++) { | |
| load_key(xmm_key_tmp0, key, (0x10 * i), xmm_key_shuf_mask); | |
| __ aesenc(xmm_result0, xmm_key_tmp0); | |
| } | |
| load_key(xmm_key_tmp0, key, (rounds[k] * 0x10), xmm_key_shuf_mask); | |
| __ aesenclast(xmm_result0, xmm_key_tmp0); | |
| __ cmpptr(len_reg, AESBlockSize); | |
| __ jcc(Assembler::less, L_processTail_insr[k]); | |
| __ movdqu(xmm_from0, Address(from, pos, Address::times_1, 0 * AESBlockSize)); | |
| __ pxor(xmm_result0, xmm_from0); | |
| __ movdqu(Address(to, pos, Address::times_1, 0 * AESBlockSize), xmm_result0); | |
| __ addptr(pos, AESBlockSize); | |
| __ subptr(len_reg, AESBlockSize); | |
| __ jmp(L_singleBlockLoopTop[k]); | |
| __ BIND(L_processTail_insr[k]); // Process the tail part of the input array | |
| __ addptr(pos, len_reg); // 1. Insert bytes from src array into xmm_from0 register | |
| __ testptr(len_reg, 8); | |
| __ jcc(Assembler::zero, L_processTail_4_insr[k]); | |
| __ subptr(pos,8); | |
| __ pinsrq(xmm_from0, Address(from, pos), 0); | |
| __ BIND(L_processTail_4_insr[k]); | |
| __ testptr(len_reg, 4); | |
| __ jcc(Assembler::zero, L_processTail_2_insr[k]); | |
| __ subptr(pos,4); | |
| __ pslldq(xmm_from0, 4); | |
| __ pinsrd(xmm_from0, Address(from, pos), 0); | |
| __ BIND(L_processTail_2_insr[k]); | |
| __ testptr(len_reg, 2); | |
| __ jcc(Assembler::zero, L_processTail_1_insr[k]); | |
| __ subptr(pos, 2); | |
| __ pslldq(xmm_from0, 2); | |
| __ pinsrw(xmm_from0, Address(from, pos), 0); | |
| __ BIND(L_processTail_1_insr[k]); | |
| __ testptr(len_reg, 1); | |
| __ jcc(Assembler::zero, L_processTail_exit_insr[k]); | |
| __ subptr(pos, 1); | |
| __ pslldq(xmm_from0, 1); | |
| __ pinsrb(xmm_from0, Address(from, pos), 0); | |
| __ BIND(L_processTail_exit_insr[k]); | |
| __ movdqu(Address(saved_encCounter_start, 0), xmm_result0); // 2. Perform pxor of the encrypted counter and plaintext Bytes. | |
| __ pxor(xmm_result0, xmm_from0); // Also the encrypted counter is saved for next invocation. | |
| __ testptr(len_reg, 8); | |
| __ jcc(Assembler::zero, L_processTail_4_extr[k]); // 3. Extract bytes from xmm_result0 into the dest. array | |
| __ pextrq(Address(to, pos), xmm_result0, 0); | |
| __ psrldq(xmm_result0, 8); | |
| __ addptr(pos, 8); | |
| __ BIND(L_processTail_4_extr[k]); | |
| __ testptr(len_reg, 4); | |
| __ jcc(Assembler::zero, L_processTail_2_extr[k]); | |
| __ pextrd(Address(to, pos), xmm_result0, 0); | |
| __ psrldq(xmm_result0, 4); | |
| __ addptr(pos, 4); | |
| __ BIND(L_processTail_2_extr[k]); | |
| __ testptr(len_reg, 2); | |
| __ jcc(Assembler::zero, L_processTail_1_extr[k]); | |
| __ pextrw(Address(to, pos), xmm_result0, 0); | |
| __ psrldq(xmm_result0, 2); | |
| __ addptr(pos, 2); | |
| __ BIND(L_processTail_1_extr[k]); | |
| __ testptr(len_reg, 1); | |
| __ jcc(Assembler::zero, L_processTail_exit_extr[k]); | |
| __ pextrb(Address(to, pos), xmm_result0, 0); | |
| __ BIND(L_processTail_exit_extr[k]); | |
| __ movl(Address(used_addr, 0), len_reg); | |
| __ jmp(L_exit); | |
| } | |
| __ BIND(L_exit); | |
| __ pshufb(xmm_curr_counter, xmm_counter_shuf_mask); //counter is shuffled back. | |
| __ movdqu(Address(counter, 0), xmm_curr_counter); //save counter back | |
| __ pop(rbx); // pop the saved RBX. | |
| #ifdef _WIN64 | |
| __ movl(rax, len_mem); | |
| __ movptr(r13, Address(rsp, saved_r13_offset * wordSize)); | |
| __ movptr(r14, Address(rsp, saved_r14_offset * wordSize)); | |
| __ addptr(rsp, 2 * wordSize); | |
| #else | |
| __ pop(rax); // return 'len' | |
| #endif | |
| __ leave(); // required for proper stackwalking of RuntimeStub frame | |
| __ ret(0); | |
| return start; | |
| } | |
| address StubGenerator::generate_cipherBlockChaining_decryptVectorAESCrypt() { | |
| assert(VM_Version::supports_avx512_vaes(), "need AES instructions and misaligned SSE support"); | |
| __ align(CodeEntryAlignment); | |
| StubGenStubId stub_id = StubGenStubId::cipherBlockChaining_decryptAESCrypt_id; | |
| StubCodeMark mark(this, stub_id); | |
| address start = __ pc(); | |
| const Register from = c_rarg0; // source array address | |
| const Register to = c_rarg1; // destination array address | |
| const Register key = c_rarg2; // key array address | |
| const Register rvec = c_rarg3; // r byte array initialized from initvector array address | |
| // and left with the results of the last encryption block | |
| #ifndef _WIN64 | |
| const Register len_reg = c_rarg4; // src len (must be multiple of blocksize 16) | |
| #else | |
| const Address len_mem(rbp, 6 * wordSize); // length is on stack on Win64 | |
| const Register len_reg = r11; // pick the volatile windows register | |
| #endif | |
| Label Loop, Loop1, L_128, L_256, L_192, KEY_192, KEY_256, Loop2, Lcbc_dec_rem_loop, | |
| Lcbc_dec_rem_last, Lcbc_dec_ret, Lcbc_dec_rem, Lcbc_exit; | |
| __ enter(); | |
| #ifdef _WIN64 | |
| // on win64, fill len_reg from stack position | |
| __ movl(len_reg, len_mem); | |
| #else | |
| __ push(len_reg); // Save | |
| #endif | |
| __ push(rbx); | |
| __ vzeroupper(); | |
| // Temporary variable declaration for swapping key bytes | |
| const XMMRegister xmm_key_shuf_mask = xmm1; | |
| __ movdqu(xmm_key_shuf_mask, ExternalAddress(key_shuffle_mask_addr()), rbx /*rscratch*/); | |
| // Calculate number of rounds from key size: 44 for 10-rounds, 52 for 12-rounds, 60 for 14-rounds | |
| const Register rounds = rbx; | |
| __ movl(rounds, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); | |
| const XMMRegister IV = xmm0; | |
| // Load IV and broadcast value to 512-bits | |
| __ evbroadcasti64x2(IV, Address(rvec, 0), Assembler::AVX_512bit); | |
| // Temporary variables for storing round keys | |
| const XMMRegister RK0 = xmm30; | |
| const XMMRegister RK1 = xmm9; | |
| const XMMRegister RK2 = xmm18; | |
| const XMMRegister RK3 = xmm19; | |
| const XMMRegister RK4 = xmm20; | |
| const XMMRegister RK5 = xmm21; | |
| const XMMRegister RK6 = xmm22; | |
| const XMMRegister RK7 = xmm23; | |
| const XMMRegister RK8 = xmm24; | |
| const XMMRegister RK9 = xmm25; | |
| const XMMRegister RK10 = xmm26; | |
| // Load and shuffle key | |
| // the java expanded key ordering is rotated one position from what we want | |
| // so we start from 1*16 here and hit 0*16 last | |
| ev_load_key(RK1, key, 1 * 16, xmm_key_shuf_mask); | |
| ev_load_key(RK2, key, 2 * 16, xmm_key_shuf_mask); | |
| ev_load_key(RK3, key, 3 * 16, xmm_key_shuf_mask); | |
| ev_load_key(RK4, key, 4 * 16, xmm_key_shuf_mask); | |
| ev_load_key(RK5, key, 5 * 16, xmm_key_shuf_mask); | |
| ev_load_key(RK6, key, 6 * 16, xmm_key_shuf_mask); | |
| ev_load_key(RK7, key, 7 * 16, xmm_key_shuf_mask); | |
| ev_load_key(RK8, key, 8 * 16, xmm_key_shuf_mask); | |
| ev_load_key(RK9, key, 9 * 16, xmm_key_shuf_mask); | |
| ev_load_key(RK10, key, 10 * 16, xmm_key_shuf_mask); | |
| ev_load_key(RK0, key, 0*16, xmm_key_shuf_mask); | |
| // Variables for storing source cipher text | |
| const XMMRegister S0 = xmm10; | |
| const XMMRegister S1 = xmm11; | |
| const XMMRegister S2 = xmm12; | |
| const XMMRegister S3 = xmm13; | |
| const XMMRegister S4 = xmm14; | |
| const XMMRegister S5 = xmm15; | |
| const XMMRegister S6 = xmm16; | |
| const XMMRegister S7 = xmm17; | |
| // Variables for storing decrypted text | |
| const XMMRegister B0 = xmm1; | |
| const XMMRegister B1 = xmm2; | |
| const XMMRegister B2 = xmm3; | |
| const XMMRegister B3 = xmm4; | |
| const XMMRegister B4 = xmm5; | |
| const XMMRegister B5 = xmm6; | |
| const XMMRegister B6 = xmm7; | |
| const XMMRegister B7 = xmm8; | |
| __ cmpl(rounds, 44); | |
| __ jcc(Assembler::greater, KEY_192); | |
| __ jmp(Loop); | |
| __ BIND(KEY_192); | |
| const XMMRegister RK11 = xmm27; | |
| const XMMRegister RK12 = xmm28; | |
| ev_load_key(RK11, key, 11*16, xmm_key_shuf_mask); | |
| ev_load_key(RK12, key, 12*16, xmm_key_shuf_mask); | |
| __ cmpl(rounds, 52); | |
| __ jcc(Assembler::greater, KEY_256); | |
| __ jmp(Loop); | |
| __ BIND(KEY_256); | |
| const XMMRegister RK13 = xmm29; | |
| const XMMRegister RK14 = xmm31; | |
| ev_load_key(RK13, key, 13*16, xmm_key_shuf_mask); | |
| ev_load_key(RK14, key, 14*16, xmm_key_shuf_mask); | |
| __ BIND(Loop); | |
| __ cmpl(len_reg, 512); | |
| __ jcc(Assembler::below, Lcbc_dec_rem); | |
| __ BIND(Loop1); | |
| __ subl(len_reg, 512); | |
| __ evmovdquq(S0, Address(from, 0 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(S1, Address(from, 1 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(S2, Address(from, 2 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(S3, Address(from, 3 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(S4, Address(from, 4 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(S5, Address(from, 5 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(S6, Address(from, 6 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(S7, Address(from, 7 * 64), Assembler::AVX_512bit); | |
| __ leaq(from, Address(from, 8 * 64)); | |
| __ evpxorq(B0, S0, RK1, Assembler::AVX_512bit); | |
| __ evpxorq(B1, S1, RK1, Assembler::AVX_512bit); | |
| __ evpxorq(B2, S2, RK1, Assembler::AVX_512bit); | |
| __ evpxorq(B3, S3, RK1, Assembler::AVX_512bit); | |
| __ evpxorq(B4, S4, RK1, Assembler::AVX_512bit); | |
| __ evpxorq(B5, S5, RK1, Assembler::AVX_512bit); | |
| __ evpxorq(B6, S6, RK1, Assembler::AVX_512bit); | |
| __ evpxorq(B7, S7, RK1, Assembler::AVX_512bit); | |
| __ evalignq(IV, S0, IV, 0x06); | |
| __ evalignq(S0, S1, S0, 0x06); | |
| __ evalignq(S1, S2, S1, 0x06); | |
| __ evalignq(S2, S3, S2, 0x06); | |
| __ evalignq(S3, S4, S3, 0x06); | |
| __ evalignq(S4, S5, S4, 0x06); | |
| __ evalignq(S5, S6, S5, 0x06); | |
| __ evalignq(S6, S7, S6, 0x06); | |
| roundDec(RK2); | |
| roundDec(RK3); | |
| roundDec(RK4); | |
| roundDec(RK5); | |
| roundDec(RK6); | |
| roundDec(RK7); | |
| roundDec(RK8); | |
| roundDec(RK9); | |
| roundDec(RK10); | |
| __ cmpl(rounds, 44); | |
| __ jcc(Assembler::belowEqual, L_128); | |
| roundDec(RK11); | |
| roundDec(RK12); | |
| __ cmpl(rounds, 52); | |
| __ jcc(Assembler::belowEqual, L_192); | |
| roundDec(RK13); | |
| roundDec(RK14); | |
| __ BIND(L_256); | |
| roundDeclast(RK0); | |
| __ jmp(Loop2); | |
| __ BIND(L_128); | |
| roundDeclast(RK0); | |
| __ jmp(Loop2); | |
| __ BIND(L_192); | |
| roundDeclast(RK0); | |
| __ BIND(Loop2); | |
| __ evpxorq(B0, B0, IV, Assembler::AVX_512bit); | |
| __ evpxorq(B1, B1, S0, Assembler::AVX_512bit); | |
| __ evpxorq(B2, B2, S1, Assembler::AVX_512bit); | |
| __ evpxorq(B3, B3, S2, Assembler::AVX_512bit); | |
| __ evpxorq(B4, B4, S3, Assembler::AVX_512bit); | |
| __ evpxorq(B5, B5, S4, Assembler::AVX_512bit); | |
| __ evpxorq(B6, B6, S5, Assembler::AVX_512bit); | |
| __ evpxorq(B7, B7, S6, Assembler::AVX_512bit); | |
| __ evmovdquq(IV, S7, Assembler::AVX_512bit); | |
| __ evmovdquq(Address(to, 0 * 64), B0, Assembler::AVX_512bit); | |
| __ evmovdquq(Address(to, 1 * 64), B1, Assembler::AVX_512bit); | |
| __ evmovdquq(Address(to, 2 * 64), B2, Assembler::AVX_512bit); | |
| __ evmovdquq(Address(to, 3 * 64), B3, Assembler::AVX_512bit); | |
| __ evmovdquq(Address(to, 4 * 64), B4, Assembler::AVX_512bit); | |
| __ evmovdquq(Address(to, 5 * 64), B5, Assembler::AVX_512bit); | |
| __ evmovdquq(Address(to, 6 * 64), B6, Assembler::AVX_512bit); | |
| __ evmovdquq(Address(to, 7 * 64), B7, Assembler::AVX_512bit); | |
| __ leaq(to, Address(to, 8 * 64)); | |
| __ jmp(Loop); | |
| __ BIND(Lcbc_dec_rem); | |
| __ evshufi64x2(IV, IV, IV, 0x03, Assembler::AVX_512bit); | |
| __ BIND(Lcbc_dec_rem_loop); | |
| __ subl(len_reg, 16); | |
| __ jcc(Assembler::carrySet, Lcbc_dec_ret); | |
| __ movdqu(S0, Address(from, 0)); | |
| __ evpxorq(B0, S0, RK1, Assembler::AVX_512bit); | |
| __ vaesdec(B0, B0, RK2, Assembler::AVX_512bit); | |
| __ vaesdec(B0, B0, RK3, Assembler::AVX_512bit); | |
| __ vaesdec(B0, B0, RK4, Assembler::AVX_512bit); | |
| __ vaesdec(B0, B0, RK5, Assembler::AVX_512bit); | |
| __ vaesdec(B0, B0, RK6, Assembler::AVX_512bit); | |
| __ vaesdec(B0, B0, RK7, Assembler::AVX_512bit); | |
| __ vaesdec(B0, B0, RK8, Assembler::AVX_512bit); | |
| __ vaesdec(B0, B0, RK9, Assembler::AVX_512bit); | |
| __ vaesdec(B0, B0, RK10, Assembler::AVX_512bit); | |
| __ cmpl(rounds, 44); | |
| __ jcc(Assembler::belowEqual, Lcbc_dec_rem_last); | |
| __ vaesdec(B0, B0, RK11, Assembler::AVX_512bit); | |
| __ vaesdec(B0, B0, RK12, Assembler::AVX_512bit); | |
| __ cmpl(rounds, 52); | |
| __ jcc(Assembler::belowEqual, Lcbc_dec_rem_last); | |
| __ vaesdec(B0, B0, RK13, Assembler::AVX_512bit); | |
| __ vaesdec(B0, B0, RK14, Assembler::AVX_512bit); | |
| __ BIND(Lcbc_dec_rem_last); | |
| __ vaesdeclast(B0, B0, RK0, Assembler::AVX_512bit); | |
| __ evpxorq(B0, B0, IV, Assembler::AVX_512bit); | |
| __ evmovdquq(IV, S0, Assembler::AVX_512bit); | |
| __ movdqu(Address(to, 0), B0); | |
| __ leaq(from, Address(from, 16)); | |
| __ leaq(to, Address(to, 16)); | |
| __ jmp(Lcbc_dec_rem_loop); | |
| __ BIND(Lcbc_dec_ret); | |
| __ movdqu(Address(rvec, 0), IV); | |
| // Zero out the round keys | |
| __ evpxorq(RK0, RK0, RK0, Assembler::AVX_512bit); | |
| __ evpxorq(RK1, RK1, RK1, Assembler::AVX_512bit); | |
| __ evpxorq(RK2, RK2, RK2, Assembler::AVX_512bit); | |
| __ evpxorq(RK3, RK3, RK3, Assembler::AVX_512bit); | |
| __ evpxorq(RK4, RK4, RK4, Assembler::AVX_512bit); | |
| __ evpxorq(RK5, RK5, RK5, Assembler::AVX_512bit); | |
| __ evpxorq(RK6, RK6, RK6, Assembler::AVX_512bit); | |
| __ evpxorq(RK7, RK7, RK7, Assembler::AVX_512bit); | |
| __ evpxorq(RK8, RK8, RK8, Assembler::AVX_512bit); | |
| __ evpxorq(RK9, RK9, RK9, Assembler::AVX_512bit); | |
| __ evpxorq(RK10, RK10, RK10, Assembler::AVX_512bit); | |
| __ cmpl(rounds, 44); | |
| __ jcc(Assembler::belowEqual, Lcbc_exit); | |
| __ evpxorq(RK11, RK11, RK11, Assembler::AVX_512bit); | |
| __ evpxorq(RK12, RK12, RK12, Assembler::AVX_512bit); | |
| __ cmpl(rounds, 52); | |
| __ jcc(Assembler::belowEqual, Lcbc_exit); | |
| __ evpxorq(RK13, RK13, RK13, Assembler::AVX_512bit); | |
| __ evpxorq(RK14, RK14, RK14, Assembler::AVX_512bit); | |
| __ BIND(Lcbc_exit); | |
| __ vzeroupper(); | |
| __ pop(rbx); | |
| #ifdef _WIN64 | |
| __ movl(rax, len_mem); | |
| #else | |
| __ pop(rax); // return length | |
| #endif | |
| __ leave(); // required for proper stackwalking of RuntimeStub frame | |
| __ ret(0); | |
| return start; | |
| } | |
| // Arguments: | |
| // | |
| // Inputs: | |
| // c_rarg0 - source byte array address | |
| // c_rarg1 - destination byte array address | |
| // c_rarg2 - K (key) in little endian int array | |
| // | |
| address StubGenerator::generate_aescrypt_encryptBlock() { | |
| assert(UseAES, "need AES instructions and misaligned SSE support"); | |
| __ align(CodeEntryAlignment); | |
| StubGenStubId stub_id = StubGenStubId::aescrypt_encryptBlock_id; | |
| StubCodeMark mark(this, stub_id); | |
| Label L_doLast; | |
| address start = __ pc(); | |
| const Register from = c_rarg0; // source array address | |
| const Register to = c_rarg1; // destination array address | |
| const Register key = c_rarg2; // key array address | |
| const Register keylen = rax; | |
| const XMMRegister xmm_result = xmm0; | |
| const XMMRegister xmm_key_shuf_mask = xmm1; | |
| // On win64 xmm6-xmm15 must be preserved so don't use them. | |
| const XMMRegister xmm_temp1 = xmm2; | |
| const XMMRegister xmm_temp2 = xmm3; | |
| const XMMRegister xmm_temp3 = xmm4; | |
| const XMMRegister xmm_temp4 = xmm5; | |
| __ enter(); // required for proper stackwalking of RuntimeStub frame | |
| // keylen could be only {11, 13, 15} * 4 = {44, 52, 60} | |
| __ movl(keylen, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); | |
| __ movdqu(xmm_key_shuf_mask, ExternalAddress(key_shuffle_mask_addr()), r10 /*rscratch*/); | |
| __ movdqu(xmm_result, Address(from, 0)); // get 16 bytes of input | |
| // For encryption, the java expanded key ordering is just what we need | |
| // we don't know if the key is aligned, hence not using load-execute form | |
| load_key(xmm_temp1, key, 0x00, xmm_key_shuf_mask); | |
| __ pxor(xmm_result, xmm_temp1); | |
| load_key(xmm_temp1, key, 0x10, xmm_key_shuf_mask); | |
| load_key(xmm_temp2, key, 0x20, xmm_key_shuf_mask); | |
| load_key(xmm_temp3, key, 0x30, xmm_key_shuf_mask); | |
| load_key(xmm_temp4, key, 0x40, xmm_key_shuf_mask); | |
| __ aesenc(xmm_result, xmm_temp1); | |
| __ aesenc(xmm_result, xmm_temp2); | |
| __ aesenc(xmm_result, xmm_temp3); | |
| __ aesenc(xmm_result, xmm_temp4); | |
| load_key(xmm_temp1, key, 0x50, xmm_key_shuf_mask); | |
| load_key(xmm_temp2, key, 0x60, xmm_key_shuf_mask); | |
| load_key(xmm_temp3, key, 0x70, xmm_key_shuf_mask); | |
| load_key(xmm_temp4, key, 0x80, xmm_key_shuf_mask); | |
| __ aesenc(xmm_result, xmm_temp1); | |
| __ aesenc(xmm_result, xmm_temp2); | |
| __ aesenc(xmm_result, xmm_temp3); | |
| __ aesenc(xmm_result, xmm_temp4); | |
| load_key(xmm_temp1, key, 0x90, xmm_key_shuf_mask); | |
| load_key(xmm_temp2, key, 0xa0, xmm_key_shuf_mask); | |
| __ cmpl(keylen, 44); | |
| __ jccb(Assembler::equal, L_doLast); | |
| __ aesenc(xmm_result, xmm_temp1); | |
| __ aesenc(xmm_result, xmm_temp2); | |
| load_key(xmm_temp1, key, 0xb0, xmm_key_shuf_mask); | |
| load_key(xmm_temp2, key, 0xc0, xmm_key_shuf_mask); | |
| __ cmpl(keylen, 52); | |
| __ jccb(Assembler::equal, L_doLast); | |
| __ aesenc(xmm_result, xmm_temp1); | |
| __ aesenc(xmm_result, xmm_temp2); | |
| load_key(xmm_temp1, key, 0xd0, xmm_key_shuf_mask); | |
| load_key(xmm_temp2, key, 0xe0, xmm_key_shuf_mask); | |
| __ BIND(L_doLast); | |
| __ aesenc(xmm_result, xmm_temp1); | |
| __ aesenclast(xmm_result, xmm_temp2); | |
| __ movdqu(Address(to, 0), xmm_result); // store the result | |
| __ xorptr(rax, rax); // return 0 | |
| __ leave(); // required for proper stackwalking of RuntimeStub frame | |
| __ ret(0); | |
| return start; | |
| } | |
| // Arguments: | |
| // | |
| // Inputs: | |
| // c_rarg0 - source byte array address | |
| // c_rarg1 - destination byte array address | |
| // c_rarg2 - K (key) in little endian int array | |
| // | |
| address StubGenerator::generate_aescrypt_decryptBlock() { | |
| assert(UseAES, "need AES instructions and misaligned SSE support"); | |
| __ align(CodeEntryAlignment); | |
| StubGenStubId stub_id = StubGenStubId::aescrypt_decryptBlock_id; | |
| StubCodeMark mark(this, stub_id); | |
| Label L_doLast; | |
| address start = __ pc(); | |
| const Register from = c_rarg0; // source array address | |
| const Register to = c_rarg1; // destination array address | |
| const Register key = c_rarg2; // key array address | |
| const Register keylen = rax; | |
| const XMMRegister xmm_result = xmm0; | |
| const XMMRegister xmm_key_shuf_mask = xmm1; | |
| // On win64 xmm6-xmm15 must be preserved so don't use them. | |
| const XMMRegister xmm_temp1 = xmm2; | |
| const XMMRegister xmm_temp2 = xmm3; | |
| const XMMRegister xmm_temp3 = xmm4; | |
| const XMMRegister xmm_temp4 = xmm5; | |
| __ enter(); // required for proper stackwalking of RuntimeStub frame | |
| // keylen could be only {11, 13, 15} * 4 = {44, 52, 60} | |
| __ movl(keylen, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); | |
| __ movdqu(xmm_key_shuf_mask, ExternalAddress(key_shuffle_mask_addr()), r10 /*rscratch*/); | |
| __ movdqu(xmm_result, Address(from, 0)); | |
| // for decryption java expanded key ordering is rotated one position from what we want | |
| // so we start from 0x10 here and hit 0x00 last | |
| // we don't know if the key is aligned, hence not using load-execute form | |
| load_key(xmm_temp1, key, 0x10, xmm_key_shuf_mask); | |
| load_key(xmm_temp2, key, 0x20, xmm_key_shuf_mask); | |
| load_key(xmm_temp3, key, 0x30, xmm_key_shuf_mask); | |
| load_key(xmm_temp4, key, 0x40, xmm_key_shuf_mask); | |
| __ pxor (xmm_result, xmm_temp1); | |
| __ aesdec(xmm_result, xmm_temp2); | |
| __ aesdec(xmm_result, xmm_temp3); | |
| __ aesdec(xmm_result, xmm_temp4); | |
| load_key(xmm_temp1, key, 0x50, xmm_key_shuf_mask); | |
| load_key(xmm_temp2, key, 0x60, xmm_key_shuf_mask); | |
| load_key(xmm_temp3, key, 0x70, xmm_key_shuf_mask); | |
| load_key(xmm_temp4, key, 0x80, xmm_key_shuf_mask); | |
| __ aesdec(xmm_result, xmm_temp1); | |
| __ aesdec(xmm_result, xmm_temp2); | |
| __ aesdec(xmm_result, xmm_temp3); | |
| __ aesdec(xmm_result, xmm_temp4); | |
| load_key(xmm_temp1, key, 0x90, xmm_key_shuf_mask); | |
| load_key(xmm_temp2, key, 0xa0, xmm_key_shuf_mask); | |
| load_key(xmm_temp3, key, 0x00, xmm_key_shuf_mask); | |
| __ cmpl(keylen, 44); | |
| __ jccb(Assembler::equal, L_doLast); | |
| __ aesdec(xmm_result, xmm_temp1); | |
| __ aesdec(xmm_result, xmm_temp2); | |
| load_key(xmm_temp1, key, 0xb0, xmm_key_shuf_mask); | |
| load_key(xmm_temp2, key, 0xc0, xmm_key_shuf_mask); | |
| __ cmpl(keylen, 52); | |
| __ jccb(Assembler::equal, L_doLast); | |
| __ aesdec(xmm_result, xmm_temp1); | |
| __ aesdec(xmm_result, xmm_temp2); | |
| load_key(xmm_temp1, key, 0xd0, xmm_key_shuf_mask); | |
| load_key(xmm_temp2, key, 0xe0, xmm_key_shuf_mask); | |
| __ BIND(L_doLast); | |
| __ aesdec(xmm_result, xmm_temp1); | |
| __ aesdec(xmm_result, xmm_temp2); | |
| // for decryption the aesdeclast operation is always on key+0x00 | |
| __ aesdeclast(xmm_result, xmm_temp3); | |
| __ movdqu(Address(to, 0), xmm_result); // store the result | |
| __ xorptr(rax, rax); // return 0 | |
| __ leave(); // required for proper stackwalking of RuntimeStub frame | |
| __ ret(0); | |
| return start; | |
| } | |
| // Arguments: | |
| // | |
| // Inputs: | |
| // c_rarg0 - source byte array address | |
| // c_rarg1 - destination byte array address | |
| // c_rarg2 - K (key) in little endian int array | |
| // c_rarg3 - r vector byte array address | |
| // c_rarg4 - input length | |
| // | |
| // Output: | |
| // rax - input length | |
| // | |
| address StubGenerator::generate_cipherBlockChaining_encryptAESCrypt() { | |
| assert(UseAES, "need AES instructions and misaligned SSE support"); | |
| __ align(CodeEntryAlignment); | |
| StubGenStubId stub_id = StubGenStubId::cipherBlockChaining_encryptAESCrypt_id; | |
| StubCodeMark mark(this, stub_id); | |
| address start = __ pc(); | |
| Label L_exit, L_key_192_256, L_key_256, L_loopTop_128, L_loopTop_192, L_loopTop_256; | |
| const Register from = c_rarg0; // source array address | |
| const Register to = c_rarg1; // destination array address | |
| const Register key = c_rarg2; // key array address | |
| const Register rvec = c_rarg3; // r byte array initialized from initvector array address | |
| // and left with the results of the last encryption block | |
| #ifdef _WIN64 | |
| const Address len_mem(rbp, 6 * wordSize); // length is on stack on Win64 | |
| const Register len_reg = r11; // pick the volatile windows register | |
| #else | |
| const Register len_reg = c_rarg4; // src len (must be multiple of blocksize 16) | |
| #endif | |
| const Register pos = rax; | |
| // xmm register assignments for the loops below | |
| const XMMRegister xmm_result = xmm0; | |
| const XMMRegister xmm_temp = xmm1; | |
| // keys 0-10 preloaded into xmm2-xmm12 | |
| const int XMM_REG_NUM_KEY_FIRST = 2; | |
| const int XMM_REG_NUM_KEY_LAST = 15; | |
| const XMMRegister xmm_key0 = as_XMMRegister(XMM_REG_NUM_KEY_FIRST); | |
| const XMMRegister xmm_key10 = as_XMMRegister(XMM_REG_NUM_KEY_FIRST+10); | |
| const XMMRegister xmm_key11 = as_XMMRegister(XMM_REG_NUM_KEY_FIRST+11); | |
| const XMMRegister xmm_key12 = as_XMMRegister(XMM_REG_NUM_KEY_FIRST+12); | |
| const XMMRegister xmm_key13 = as_XMMRegister(XMM_REG_NUM_KEY_FIRST+13); | |
| __ enter(); // required for proper stackwalking of RuntimeStub frame | |
| #ifdef _WIN64 | |
| // on win64, fill len_reg from stack position | |
| __ movl(len_reg, len_mem); | |
| #else | |
| __ push(len_reg); // Save | |
| #endif | |
| const XMMRegister xmm_key_shuf_mask = xmm_temp; // used temporarily to swap key bytes up front | |
| __ movdqu(xmm_key_shuf_mask, ExternalAddress(key_shuffle_mask_addr()), r10 /*rscratch*/); | |
| // load up xmm regs xmm2 thru xmm12 with key 0x00 - 0xa0 | |
| for (int rnum = XMM_REG_NUM_KEY_FIRST, offset = 0x00; rnum <= XMM_REG_NUM_KEY_FIRST+10; rnum++) { | |
| load_key(as_XMMRegister(rnum), key, offset, xmm_key_shuf_mask); | |
| offset += 0x10; | |
| } | |
| __ movdqu(xmm_result, Address(rvec, 0x00)); // initialize xmm_result with r vec | |
| // now split to different paths depending on the keylen (len in ints of AESCrypt.KLE array (52=192, or 60=256)) | |
| __ movl(rax, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); | |
| __ cmpl(rax, 44); | |
| __ jcc(Assembler::notEqual, L_key_192_256); | |
| // 128 bit code follows here | |
| __ movptr(pos, 0); | |
| __ align(OptoLoopAlignment); | |
| __ BIND(L_loopTop_128); | |
| __ movdqu(xmm_temp, Address(from, pos, Address::times_1, 0)); // get next 16 bytes of input | |
| __ pxor (xmm_result, xmm_temp); // xor with the current r vector | |
| __ pxor (xmm_result, xmm_key0); // do the aes rounds | |
| for (int rnum = XMM_REG_NUM_KEY_FIRST + 1; rnum <= XMM_REG_NUM_KEY_FIRST + 9; rnum++) { | |
| __ aesenc(xmm_result, as_XMMRegister(rnum)); | |
| } | |
| __ aesenclast(xmm_result, xmm_key10); | |
| __ movdqu(Address(to, pos, Address::times_1, 0), xmm_result); // store into the next 16 bytes of output | |
| // no need to store r to memory until we exit | |
| __ addptr(pos, AESBlockSize); | |
| __ subptr(len_reg, AESBlockSize); | |
| __ jcc(Assembler::notEqual, L_loopTop_128); | |
| __ BIND(L_exit); | |
| __ movdqu(Address(rvec, 0), xmm_result); // final value of r stored in rvec of CipherBlockChaining object | |
| #ifdef _WIN64 | |
| __ movl(rax, len_mem); | |
| #else | |
| __ pop(rax); // return length | |
| #endif | |
| __ leave(); // required for proper stackwalking of RuntimeStub frame | |
| __ ret(0); | |
| __ BIND(L_key_192_256); | |
| // here rax = len in ints of AESCrypt.KLE array (52=192, or 60=256) | |
| load_key(xmm_key11, key, 0xb0, xmm_key_shuf_mask); | |
| load_key(xmm_key12, key, 0xc0, xmm_key_shuf_mask); | |
| __ cmpl(rax, 52); | |
| __ jcc(Assembler::notEqual, L_key_256); | |
| // 192-bit code follows here (could be changed to use more xmm registers) | |
| __ movptr(pos, 0); | |
| __ align(OptoLoopAlignment); | |
| __ BIND(L_loopTop_192); | |
| __ movdqu(xmm_temp, Address(from, pos, Address::times_1, 0)); // get next 16 bytes of input | |
| __ pxor (xmm_result, xmm_temp); // xor with the current r vector | |
| __ pxor (xmm_result, xmm_key0); // do the aes rounds | |
| for (int rnum = XMM_REG_NUM_KEY_FIRST + 1; rnum <= XMM_REG_NUM_KEY_FIRST + 11; rnum++) { | |
| __ aesenc(xmm_result, as_XMMRegister(rnum)); | |
| } | |
| __ aesenclast(xmm_result, xmm_key12); | |
| __ movdqu(Address(to, pos, Address::times_1, 0), xmm_result); // store into the next 16 bytes of output | |
| // no need to store r to memory until we exit | |
| __ addptr(pos, AESBlockSize); | |
| __ subptr(len_reg, AESBlockSize); | |
| __ jcc(Assembler::notEqual, L_loopTop_192); | |
| __ jmp(L_exit); | |
| __ BIND(L_key_256); | |
| // 256-bit code follows here (could be changed to use more xmm registers) | |
| load_key(xmm_key13, key, 0xd0, xmm_key_shuf_mask); | |
| __ movptr(pos, 0); | |
| __ align(OptoLoopAlignment); | |
| __ BIND(L_loopTop_256); | |
| __ movdqu(xmm_temp, Address(from, pos, Address::times_1, 0)); // get next 16 bytes of input | |
| __ pxor (xmm_result, xmm_temp); // xor with the current r vector | |
| __ pxor (xmm_result, xmm_key0); // do the aes rounds | |
| for (int rnum = XMM_REG_NUM_KEY_FIRST + 1; rnum <= XMM_REG_NUM_KEY_FIRST + 13; rnum++) { | |
| __ aesenc(xmm_result, as_XMMRegister(rnum)); | |
| } | |
| load_key(xmm_temp, key, 0xe0, r10 /*rscratch*/); | |
| __ aesenclast(xmm_result, xmm_temp); | |
| __ movdqu(Address(to, pos, Address::times_1, 0), xmm_result); // store into the next 16 bytes of output | |
| // no need to store r to memory until we exit | |
| __ addptr(pos, AESBlockSize); | |
| __ subptr(len_reg, AESBlockSize); | |
| __ jcc(Assembler::notEqual, L_loopTop_256); | |
| __ jmp(L_exit); | |
| return start; | |
| } | |
| // This is a version of CBC/AES Decrypt which does 4 blocks in a loop at a time | |
| // to hide instruction latency | |
| // | |
| // Arguments: | |
| // | |
| // Inputs: | |
| // c_rarg0 - source byte array address | |
| // c_rarg1 - destination byte array address | |
| // c_rarg2 - K (key) in little endian int array | |
| // c_rarg3 - r vector byte array address | |
| // c_rarg4 - input length | |
| // | |
| // Output: | |
| // rax - input length | |
| // | |
| address StubGenerator::generate_cipherBlockChaining_decryptAESCrypt_Parallel() { | |
| assert(UseAES, "need AES instructions and misaligned SSE support"); | |
| __ align(CodeEntryAlignment); | |
| StubGenStubId stub_id = StubGenStubId::cipherBlockChaining_decryptAESCrypt_id; | |
| StubCodeMark mark(this, stub_id); | |
| address start = __ pc(); | |
| const Register from = c_rarg0; // source array address | |
| const Register to = c_rarg1; // destination array address | |
| const Register key = c_rarg2; // key array address | |
| const Register rvec = c_rarg3; // r byte array initialized from initvector array address | |
| // and left with the results of the last encryption block | |
| #ifndef _WIN64 | |
| const Register len_reg = c_rarg4; // src len (must be multiple of blocksize 16) | |
| #else | |
| const Address len_mem(rbp, 6 * wordSize); // length is on stack on Win64 | |
| const Register len_reg = r11; // pick the volatile windows register | |
| #endif | |
| const Register pos = rax; | |
| const int PARALLEL_FACTOR = 4; | |
| const int ROUNDS[3] = { 10, 12, 14 }; // aes rounds for key128, key192, key256 | |
| Label L_exit; | |
| Label L_singleBlock_loopTopHead[3]; // 128, 192, 256 | |
| Label L_singleBlock_loopTopHead2[3]; // 128, 192, 256 | |
| Label L_singleBlock_loopTop[3]; // 128, 192, 256 | |
| Label L_multiBlock_loopTopHead[3]; // 128, 192, 256 | |
| Label L_multiBlock_loopTop[3]; // 128, 192, 256 | |
| // keys 0-10 preloaded into xmm5-xmm15 | |
| const int XMM_REG_NUM_KEY_FIRST = 5; | |
| const int XMM_REG_NUM_KEY_LAST = 15; | |
| const XMMRegister xmm_key_first = as_XMMRegister(XMM_REG_NUM_KEY_FIRST); | |
| const XMMRegister xmm_key_last = as_XMMRegister(XMM_REG_NUM_KEY_LAST); | |
| __ enter(); // required for proper stackwalking of RuntimeStub frame | |
| #ifdef _WIN64 | |
| // on win64, fill len_reg from stack position | |
| __ movl(len_reg, len_mem); | |
| #else | |
| __ push(len_reg); // Save | |
| #endif | |
| __ push(rbx); | |
| // the java expanded key ordering is rotated one position from what we want | |
| // so we start from 0x10 here and hit 0x00 last | |
| const XMMRegister xmm_key_shuf_mask = xmm1; // used temporarily to swap key bytes up front | |
| __ movdqu(xmm_key_shuf_mask, ExternalAddress(key_shuffle_mask_addr()), rbx /*rscratch*/); | |
| // load up xmm regs 5 thru 15 with key 0x10 - 0xa0 - 0x00 | |
| for (int rnum = XMM_REG_NUM_KEY_FIRST, offset = 0x10; rnum < XMM_REG_NUM_KEY_LAST; rnum++) { | |
| load_key(as_XMMRegister(rnum), key, offset, xmm_key_shuf_mask); | |
| offset += 0x10; | |
| } | |
| load_key(xmm_key_last, key, 0x00, xmm_key_shuf_mask); | |
| const XMMRegister xmm_prev_block_cipher = xmm1; // holds cipher of previous block | |
| // registers holding the four results in the parallelized loop | |
| const XMMRegister xmm_result0 = xmm0; | |
| const XMMRegister xmm_result1 = xmm2; | |
| const XMMRegister xmm_result2 = xmm3; | |
| const XMMRegister xmm_result3 = xmm4; | |
| __ movdqu(xmm_prev_block_cipher, Address(rvec, 0x00)); // initialize with initial rvec | |
| __ xorptr(pos, pos); | |
| // now split to different paths depending on the keylen (len in ints of AESCrypt.KLE array (52=192, or 60=256)) | |
| __ movl(rbx, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); | |
| __ cmpl(rbx, 52); | |
| __ jcc(Assembler::equal, L_multiBlock_loopTopHead[1]); | |
| __ cmpl(rbx, 60); | |
| __ jcc(Assembler::equal, L_multiBlock_loopTopHead[2]); | |
| #define DoFour(opc, src_reg) \ | |
| __ opc(xmm_result0, src_reg); \ | |
| __ opc(xmm_result1, src_reg); \ | |
| __ opc(xmm_result2, src_reg); \ | |
| __ opc(xmm_result3, src_reg); \ | |
| for (int k = 0; k < 3; ++k) { | |
| __ BIND(L_multiBlock_loopTopHead[k]); | |
| if (k != 0) { | |
| __ cmpptr(len_reg, PARALLEL_FACTOR * AESBlockSize); // see if at least 4 blocks left | |
| __ jcc(Assembler::less, L_singleBlock_loopTopHead2[k]); | |
| } | |
| if (k == 1) { | |
| __ subptr(rsp, 6 * wordSize); | |
| __ movdqu(Address(rsp, 0), xmm15); //save last_key from xmm15 | |
| load_key(xmm15, key, 0xb0, rbx /*rscratch*/); // 0xb0; 192-bit key goes up to 0xc0 | |
| __ movdqu(Address(rsp, 2 * wordSize), xmm15); | |
| load_key(xmm1, key, 0xc0, rbx /*rscratch*/); // 0xc0; | |
| __ movdqu(Address(rsp, 4 * wordSize), xmm1); | |
| } else if (k == 2) { | |
| __ subptr(rsp, 10 * wordSize); | |
| __ movdqu(Address(rsp, 0), xmm15); //save last_key from xmm15 | |
| load_key(xmm15, key, 0xd0, rbx /*rscratch*/); // 0xd0; 256-bit key goes up to 0xe0 | |
| __ movdqu(Address(rsp, 6 * wordSize), xmm15); | |
| load_key(xmm1, key, 0xe0, rbx /*rscratch*/); // 0xe0; | |
| __ movdqu(Address(rsp, 8 * wordSize), xmm1); | |
| load_key(xmm15, key, 0xb0, rbx /*rscratch*/); // 0xb0; | |
| __ movdqu(Address(rsp, 2 * wordSize), xmm15); | |
| load_key(xmm1, key, 0xc0, rbx /*rscratch*/); // 0xc0; | |
| __ movdqu(Address(rsp, 4 * wordSize), xmm1); | |
| } | |
| __ align(OptoLoopAlignment); | |
| __ BIND(L_multiBlock_loopTop[k]); | |
| __ cmpptr(len_reg, PARALLEL_FACTOR * AESBlockSize); // see if at least 4 blocks left | |
| __ jcc(Assembler::less, L_singleBlock_loopTopHead[k]); | |
| if (k != 0) { | |
| __ movdqu(xmm15, Address(rsp, 2 * wordSize)); | |
| __ movdqu(xmm1, Address(rsp, 4 * wordSize)); | |
| } | |
| __ movdqu(xmm_result0, Address(from, pos, Address::times_1, 0 * AESBlockSize)); // get next 4 blocks into xmmresult registers | |
| __ movdqu(xmm_result1, Address(from, pos, Address::times_1, 1 * AESBlockSize)); | |
| __ movdqu(xmm_result2, Address(from, pos, Address::times_1, 2 * AESBlockSize)); | |
| __ movdqu(xmm_result3, Address(from, pos, Address::times_1, 3 * AESBlockSize)); | |
| DoFour(pxor, xmm_key_first); | |
| if (k == 0) { | |
| for (int rnum = 1; rnum < ROUNDS[k]; rnum++) { | |
| DoFour(aesdec, as_XMMRegister(rnum + XMM_REG_NUM_KEY_FIRST)); | |
| } | |
| DoFour(aesdeclast, xmm_key_last); | |
| } else if (k == 1) { | |
| for (int rnum = 1; rnum <= ROUNDS[k]-2; rnum++) { | |
| DoFour(aesdec, as_XMMRegister(rnum + XMM_REG_NUM_KEY_FIRST)); | |
| } | |
| __ movdqu(xmm_key_last, Address(rsp, 0)); // xmm15 needs to be loaded again. | |
| DoFour(aesdec, xmm1); // key : 0xc0 | |
| __ movdqu(xmm_prev_block_cipher, Address(rvec, 0x00)); // xmm1 needs to be loaded again | |
| DoFour(aesdeclast, xmm_key_last); | |
| } else if (k == 2) { | |
| for (int rnum = 1; rnum <= ROUNDS[k] - 4; rnum++) { | |
| DoFour(aesdec, as_XMMRegister(rnum + XMM_REG_NUM_KEY_FIRST)); | |
| } | |
| DoFour(aesdec, xmm1); // key : 0xc0 | |
| __ movdqu(xmm15, Address(rsp, 6 * wordSize)); | |
| __ movdqu(xmm1, Address(rsp, 8 * wordSize)); | |
| DoFour(aesdec, xmm15); // key : 0xd0 | |
| __ movdqu(xmm_key_last, Address(rsp, 0)); // xmm15 needs to be loaded again. | |
| DoFour(aesdec, xmm1); // key : 0xe0 | |
| __ movdqu(xmm_prev_block_cipher, Address(rvec, 0x00)); // xmm1 needs to be loaded again | |
| DoFour(aesdeclast, xmm_key_last); | |
| } | |
| // for each result, xor with the r vector of previous cipher block | |
| __ pxor(xmm_result0, xmm_prev_block_cipher); | |
| __ movdqu(xmm_prev_block_cipher, Address(from, pos, Address::times_1, 0 * AESBlockSize)); | |
| __ pxor(xmm_result1, xmm_prev_block_cipher); | |
| __ movdqu(xmm_prev_block_cipher, Address(from, pos, Address::times_1, 1 * AESBlockSize)); | |
| __ pxor(xmm_result2, xmm_prev_block_cipher); | |
| __ movdqu(xmm_prev_block_cipher, Address(from, pos, Address::times_1, 2 * AESBlockSize)); | |
| __ pxor(xmm_result3, xmm_prev_block_cipher); | |
| __ movdqu(xmm_prev_block_cipher, Address(from, pos, Address::times_1, 3 * AESBlockSize)); // this will carry over to next set of blocks | |
| if (k != 0) { | |
| __ movdqu(Address(rvec, 0x00), xmm_prev_block_cipher); | |
| } | |
| __ movdqu(Address(to, pos, Address::times_1, 0 * AESBlockSize), xmm_result0); // store 4 results into the next 64 bytes of output | |
| __ movdqu(Address(to, pos, Address::times_1, 1 * AESBlockSize), xmm_result1); | |
| __ movdqu(Address(to, pos, Address::times_1, 2 * AESBlockSize), xmm_result2); | |
| __ movdqu(Address(to, pos, Address::times_1, 3 * AESBlockSize), xmm_result3); | |
| __ addptr(pos, PARALLEL_FACTOR * AESBlockSize); | |
| __ subptr(len_reg, PARALLEL_FACTOR * AESBlockSize); | |
| __ jmp(L_multiBlock_loopTop[k]); | |
| // registers used in the non-parallelized loops | |
| // xmm register assignments for the loops below | |
| const XMMRegister xmm_result = xmm0; | |
| const XMMRegister xmm_prev_block_cipher_save = xmm2; | |
| const XMMRegister xmm_key11 = xmm3; | |
| const XMMRegister xmm_key12 = xmm4; | |
| const XMMRegister key_tmp = xmm4; | |
| __ BIND(L_singleBlock_loopTopHead[k]); | |
| if (k == 1) { | |
| __ addptr(rsp, 6 * wordSize); | |
| } else if (k == 2) { | |
| __ addptr(rsp, 10 * wordSize); | |
| } | |
| __ cmpptr(len_reg, 0); // any blocks left?? | |
| __ jcc(Assembler::equal, L_exit); | |
| __ BIND(L_singleBlock_loopTopHead2[k]); | |
| if (k == 1) { | |
| load_key(xmm_key11, key, 0xb0, rbx /*rscratch*/); // 0xb0; 192-bit key goes up to 0xc0 | |
| load_key(xmm_key12, key, 0xc0, rbx /*rscratch*/); // 0xc0; 192-bit key goes up to 0xc0 | |
| } | |
| if (k == 2) { | |
| load_key(xmm_key11, key, 0xb0, rbx /*rscratch*/); // 0xb0; 256-bit key goes up to 0xe0 | |
| } | |
| __ align(OptoLoopAlignment); | |
| __ BIND(L_singleBlock_loopTop[k]); | |
| __ movdqu(xmm_result, Address(from, pos, Address::times_1, 0)); // get next 16 bytes of cipher input | |
| __ movdqa(xmm_prev_block_cipher_save, xmm_result); // save for next r vector | |
| __ pxor(xmm_result, xmm_key_first); // do the aes dec rounds | |
| for (int rnum = 1; rnum <= 9 ; rnum++) { | |
| __ aesdec(xmm_result, as_XMMRegister(rnum + XMM_REG_NUM_KEY_FIRST)); | |
| } | |
| if (k == 1) { | |
| __ aesdec(xmm_result, xmm_key11); | |
| __ aesdec(xmm_result, xmm_key12); | |
| } | |
| if (k == 2) { | |
| __ aesdec(xmm_result, xmm_key11); | |
| load_key(key_tmp, key, 0xc0, rbx /*rscratch*/); | |
| __ aesdec(xmm_result, key_tmp); | |
| load_key(key_tmp, key, 0xd0, rbx /*rscratch*/); | |
| __ aesdec(xmm_result, key_tmp); | |
| load_key(key_tmp, key, 0xe0, rbx /*rscratch*/); | |
| __ aesdec(xmm_result, key_tmp); | |
| } | |
| __ aesdeclast(xmm_result, xmm_key_last); // xmm15 always came from key+0 | |
| __ pxor(xmm_result, xmm_prev_block_cipher); // xor with the current r vector | |
| __ movdqu(Address(to, pos, Address::times_1, 0), xmm_result); // store into the next 16 bytes of output | |
| // no need to store r to memory until we exit | |
| __ movdqa(xmm_prev_block_cipher, xmm_prev_block_cipher_save); // set up next r vector with cipher input from this block | |
| __ addptr(pos, AESBlockSize); | |
| __ subptr(len_reg, AESBlockSize); | |
| __ jcc(Assembler::notEqual, L_singleBlock_loopTop[k]); | |
| if (k != 2) { | |
| __ jmp(L_exit); | |
| } | |
| } //for 128/192/256 | |
| __ BIND(L_exit); | |
| __ movdqu(Address(rvec, 0), xmm_prev_block_cipher); // final value of r stored in rvec of CipherBlockChaining object | |
| __ pop(rbx); | |
| #ifdef _WIN64 | |
| __ movl(rax, len_mem); | |
| #else | |
| __ pop(rax); // return length | |
| #endif | |
| __ leave(); // required for proper stackwalking of RuntimeStub frame | |
| __ ret(0); | |
| return start; | |
| } | |
| address StubGenerator::generate_electronicCodeBook_encryptAESCrypt() { | |
| __ align(CodeEntryAlignment); | |
| StubGenStubId stub_id = StubGenStubId::electronicCodeBook_encryptAESCrypt_id; | |
| StubCodeMark mark(this, stub_id); | |
| address start = __ pc(); | |
| const Register from = c_rarg0; // source array address | |
| const Register to = c_rarg1; // destination array address | |
| const Register key = c_rarg2; // key array address | |
| const Register len = c_rarg3; // src len (must be multiple of blocksize 16) | |
| __ enter(); // required for proper stackwalking of RuntimeStub frame | |
| aesecb_encrypt(from, to, key, len); | |
| __ vzeroupper(); | |
| __ leave(); // required for proper stackwalking of RuntimeStub frame | |
| __ ret(0); | |
| return start; | |
| } | |
| address StubGenerator::generate_electronicCodeBook_decryptAESCrypt() { | |
| __ align(CodeEntryAlignment); | |
| StubGenStubId stub_id = StubGenStubId::electronicCodeBook_decryptAESCrypt_id; | |
| StubCodeMark mark(this, stub_id); | |
| address start = __ pc(); | |
| const Register from = c_rarg0; // source array address | |
| const Register to = c_rarg1; // destination array address | |
| const Register key = c_rarg2; // key array address | |
| const Register len = c_rarg3; // src len (must be multiple of blocksize 16) | |
| __ enter(); // required for proper stackwalking of RuntimeStub frame | |
| aesecb_decrypt(from, to, key, len); | |
| __ vzeroupper(); | |
| __ leave(); // required for proper stackwalking of RuntimeStub frame | |
| __ ret(0); | |
| return start; | |
| } | |
| // Utility routine for increase 128bit counter (iv in CTR mode) | |
| void StubGenerator::inc_counter(Register reg, XMMRegister xmmdst, int inc_delta, Label& next_block) { | |
| __ pextrq(reg, xmmdst, 0x0); | |
| __ addq(reg, inc_delta); | |
| __ pinsrq(xmmdst, reg, 0x0); | |
| __ jcc(Assembler::carryClear, next_block); // jump if no carry | |
| __ pextrq(reg, xmmdst, 0x01); // Carry | |
| __ addq(reg, 0x01); | |
| __ pinsrq(xmmdst, reg, 0x01); //Carry end | |
| __ BIND(next_block); // next instruction | |
| } | |
| void StubGenerator::roundEnc(XMMRegister key, int rnum) { | |
| for (int xmm_reg_no = 0; xmm_reg_no <=rnum; xmm_reg_no++) { | |
| __ vaesenc(as_XMMRegister(xmm_reg_no), as_XMMRegister(xmm_reg_no), key, Assembler::AVX_512bit); | |
| } | |
| } | |
| void StubGenerator::lastroundEnc(XMMRegister key, int rnum) { | |
| for (int xmm_reg_no = 0; xmm_reg_no <=rnum; xmm_reg_no++) { | |
| __ vaesenclast(as_XMMRegister(xmm_reg_no), as_XMMRegister(xmm_reg_no), key, Assembler::AVX_512bit); | |
| } | |
| } | |
| void StubGenerator::roundDec(XMMRegister key, int rnum) { | |
| for (int xmm_reg_no = 0; xmm_reg_no <=rnum; xmm_reg_no++) { | |
| __ vaesdec(as_XMMRegister(xmm_reg_no), as_XMMRegister(xmm_reg_no), key, Assembler::AVX_512bit); | |
| } | |
| } | |
| void StubGenerator::lastroundDec(XMMRegister key, int rnum) { | |
| for (int xmm_reg_no = 0; xmm_reg_no <=rnum; xmm_reg_no++) { | |
| __ vaesdeclast(as_XMMRegister(xmm_reg_no), as_XMMRegister(xmm_reg_no), key, Assembler::AVX_512bit); | |
| } | |
| } | |
| void StubGenerator::roundDec(XMMRegister xmm_reg) { | |
| __ vaesdec(xmm1, xmm1, xmm_reg, Assembler::AVX_512bit); | |
| __ vaesdec(xmm2, xmm2, xmm_reg, Assembler::AVX_512bit); | |
| __ vaesdec(xmm3, xmm3, xmm_reg, Assembler::AVX_512bit); | |
| __ vaesdec(xmm4, xmm4, xmm_reg, Assembler::AVX_512bit); | |
| __ vaesdec(xmm5, xmm5, xmm_reg, Assembler::AVX_512bit); | |
| __ vaesdec(xmm6, xmm6, xmm_reg, Assembler::AVX_512bit); | |
| __ vaesdec(xmm7, xmm7, xmm_reg, Assembler::AVX_512bit); | |
| __ vaesdec(xmm8, xmm8, xmm_reg, Assembler::AVX_512bit); | |
| } | |
| void StubGenerator::roundDeclast(XMMRegister xmm_reg) { | |
| __ vaesdeclast(xmm1, xmm1, xmm_reg, Assembler::AVX_512bit); | |
| __ vaesdeclast(xmm2, xmm2, xmm_reg, Assembler::AVX_512bit); | |
| __ vaesdeclast(xmm3, xmm3, xmm_reg, Assembler::AVX_512bit); | |
| __ vaesdeclast(xmm4, xmm4, xmm_reg, Assembler::AVX_512bit); | |
| __ vaesdeclast(xmm5, xmm5, xmm_reg, Assembler::AVX_512bit); | |
| __ vaesdeclast(xmm6, xmm6, xmm_reg, Assembler::AVX_512bit); | |
| __ vaesdeclast(xmm7, xmm7, xmm_reg, Assembler::AVX_512bit); | |
| __ vaesdeclast(xmm8, xmm8, xmm_reg, Assembler::AVX_512bit); | |
| } | |
| // Check incoming byte offset against the int[] len. key is the pointer to the int[0]. | |
| // This check happens often, so it is important for it to be very compact. | |
| void StubGenerator::check_key_offset(Register key, int offset, int load_size) { | |
| #ifdef ASSERT | |
| Address key_length(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT)); | |
| assert((offset + load_size) % 4 == 0, "Alignment is good: %d + %d", offset, load_size); | |
| int end_offset = (offset + load_size) / 4; | |
| Label L_good; | |
| __ cmpl(key_length, end_offset); | |
| __ jccb(Assembler::greaterEqual, L_good); | |
| __ hlt(); | |
| __ bind(L_good); | |
| #endif | |
| } | |
| // Utility routine for loading a 128-bit key word in little endian format | |
| void StubGenerator::load_key(XMMRegister xmmdst, Register key, int offset, XMMRegister xmm_shuf_mask) { | |
| check_key_offset(key, offset, 16); | |
| __ movdqu(xmmdst, Address(key, offset)); | |
| __ pshufb(xmmdst, xmm_shuf_mask); | |
| } | |
| void StubGenerator::load_key(XMMRegister xmmdst, Register key, int offset, Register rscratch) { | |
| check_key_offset(key, offset, 16); | |
| __ movdqu(xmmdst, Address(key, offset)); | |
| __ pshufb(xmmdst, ExternalAddress(key_shuffle_mask_addr()), rscratch); | |
| } | |
| void StubGenerator::ev_load_key(XMMRegister xmmdst, Register key, int offset, XMMRegister xmm_shuf_mask) { | |
| check_key_offset(key, offset, 16); | |
| __ movdqu(xmmdst, Address(key, offset)); | |
| __ pshufb(xmmdst, xmm_shuf_mask); | |
| __ evshufi64x2(xmmdst, xmmdst, xmmdst, 0x0, Assembler::AVX_512bit); | |
| } | |
| void StubGenerator::ev_load_key(XMMRegister xmmdst, Register key, int offset, Register rscratch) { | |
| check_key_offset(key, offset, 16); | |
| __ movdqu(xmmdst, Address(key, offset)); | |
| __ pshufb(xmmdst, ExternalAddress(key_shuffle_mask_addr()), rscratch); | |
| __ evshufi64x2(xmmdst, xmmdst, xmmdst, 0x0, Assembler::AVX_512bit); | |
| } | |
| // Add 128-bit integers in xmmsrc1 to xmmsrc2, then place the result in xmmdst. | |
| // Clobber ktmp and rscratch. | |
| // Used by aesctr_encrypt. | |
| void StubGenerator::ev_add128(XMMRegister xmmdst, XMMRegister xmmsrc1, XMMRegister xmmsrc2, | |
| int vector_len, KRegister ktmp, XMMRegister ones) { | |
| __ vpaddq(xmmdst, xmmsrc1, xmmsrc2, vector_len); | |
| __ evpcmpuq(ktmp, xmmdst, xmmsrc2, __ lt, vector_len); // set mask[0/1] bit if addq to dst[0/1] wraps | |
| __ kshiftlbl(ktmp, ktmp, 1); // mask[1] <- mask[0], mask[0] <- 0, etc | |
| __ evpaddq(xmmdst, ktmp, xmmdst, ones, /*merge*/true, vector_len); // dst[1]++ if mask[1] set | |
| } | |
| // AES-ECB Encrypt Operation | |
| void StubGenerator::aesecb_encrypt(Register src_addr, Register dest_addr, Register key, Register len) { | |
| const Register pos = rax; | |
| const Register rounds = r12; | |
| Label NO_PARTS, LOOP, Loop_start, LOOP2, AES192, END_LOOP, AES256, REMAINDER, LAST2, END, KEY_192, KEY_256, EXIT; | |
| __ push(r13); | |
| __ push(r12); | |
| // For EVEX with VL and BW, provide a standard mask, VL = 128 will guide the merge | |
| // context for the registers used, where all instructions below are using 128-bit mode | |
| // On EVEX without VL and BW, these instructions will all be AVX. | |
| if (VM_Version::supports_avx512vlbw()) { | |
| __ movl(rax, 0xffff); | |
| __ kmovql(k1, rax); | |
| } | |
| __ push(len); // Save | |
| __ push(rbx); | |
| __ vzeroupper(); | |
| __ xorptr(pos, pos); | |
| // Calculate number of rounds based on key length(128, 192, 256):44 for 10-rounds, 52 for 12-rounds, 60 for 14-rounds | |
| __ movl(rounds, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); | |
| // Load Key shuf mask | |
| const XMMRegister xmm_key_shuf_mask = xmm31; // used temporarily to swap key bytes up front | |
| __ movdqu(xmm_key_shuf_mask, ExternalAddress(key_shuffle_mask_addr()), rbx /*rscratch*/); | |
| // Load and shuffle key based on number of rounds | |
| ev_load_key(xmm8, key, 0 * 16, xmm_key_shuf_mask); | |
| ev_load_key(xmm9, key, 1 * 16, xmm_key_shuf_mask); | |
| ev_load_key(xmm10, key, 2 * 16, xmm_key_shuf_mask); | |
| ev_load_key(xmm23, key, 3 * 16, xmm_key_shuf_mask); | |
| ev_load_key(xmm12, key, 4 * 16, xmm_key_shuf_mask); | |
| ev_load_key(xmm13, key, 5 * 16, xmm_key_shuf_mask); | |
| ev_load_key(xmm14, key, 6 * 16, xmm_key_shuf_mask); | |
| ev_load_key(xmm15, key, 7 * 16, xmm_key_shuf_mask); | |
| ev_load_key(xmm16, key, 8 * 16, xmm_key_shuf_mask); | |
| ev_load_key(xmm17, key, 9 * 16, xmm_key_shuf_mask); | |
| ev_load_key(xmm24, key, 10 * 16, xmm_key_shuf_mask); | |
| __ cmpl(rounds, 52); | |
| __ jcc(Assembler::greaterEqual, KEY_192); | |
| __ jmp(Loop_start); | |
| __ bind(KEY_192); | |
| ev_load_key(xmm19, key, 11 * 16, xmm_key_shuf_mask); | |
| ev_load_key(xmm20, key, 12 * 16, xmm_key_shuf_mask); | |
| __ cmpl(rounds, 60); | |
| __ jcc(Assembler::equal, KEY_256); | |
| __ jmp(Loop_start); | |
| __ bind(KEY_256); | |
| ev_load_key(xmm21, key, 13 * 16, xmm_key_shuf_mask); | |
| ev_load_key(xmm22, key, 14 * 16, xmm_key_shuf_mask); | |
| __ bind(Loop_start); | |
| __ movq(rbx, len); | |
| // Divide length by 16 to convert it to number of blocks | |
| __ shrq(len, 4); | |
| __ shlq(rbx, 60); | |
| __ jcc(Assembler::equal, NO_PARTS); | |
| __ addq(len, 1); | |
| // Check if number of blocks is greater than or equal to 32 | |
| // If true, 512 bytes are processed at a time (code marked by label LOOP) | |
| // If not, 16 bytes are processed (code marked by REMAINDER label) | |
| __ bind(NO_PARTS); | |
| __ movq(rbx, len); | |
| __ shrq(len, 5); | |
| __ jcc(Assembler::equal, REMAINDER); | |
| __ movl(r13, len); | |
| // Compute number of blocks that will be processed 512 bytes at a time | |
| // Subtract this from the total number of blocks which will then be processed by REMAINDER loop | |
| __ shlq(r13, 5); | |
| __ subq(rbx, r13); | |
| //Begin processing 512 bytes | |
| __ bind(LOOP); | |
| // Move 64 bytes of PT data into a zmm register, as a result 512 bytes of PT loaded in zmm0-7 | |
| __ evmovdquq(xmm0, Address(src_addr, pos, Address::times_1, 0 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(xmm1, Address(src_addr, pos, Address::times_1, 1 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(xmm2, Address(src_addr, pos, Address::times_1, 2 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(xmm3, Address(src_addr, pos, Address::times_1, 3 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(xmm4, Address(src_addr, pos, Address::times_1, 4 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(xmm5, Address(src_addr, pos, Address::times_1, 5 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(xmm6, Address(src_addr, pos, Address::times_1, 6 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(xmm7, Address(src_addr, pos, Address::times_1, 7 * 64), Assembler::AVX_512bit); | |
| // Xor with the first round key | |
| __ evpxorq(xmm0, xmm0, xmm8, Assembler::AVX_512bit); | |
| __ evpxorq(xmm1, xmm1, xmm8, Assembler::AVX_512bit); | |
| __ evpxorq(xmm2, xmm2, xmm8, Assembler::AVX_512bit); | |
| __ evpxorq(xmm3, xmm3, xmm8, Assembler::AVX_512bit); | |
| __ evpxorq(xmm4, xmm4, xmm8, Assembler::AVX_512bit); | |
| __ evpxorq(xmm5, xmm5, xmm8, Assembler::AVX_512bit); | |
| __ evpxorq(xmm6, xmm6, xmm8, Assembler::AVX_512bit); | |
| __ evpxorq(xmm7, xmm7, xmm8, Assembler::AVX_512bit); | |
| // 9 Aes encode round operations | |
| roundEnc(xmm9, 7); | |
| roundEnc(xmm10, 7); | |
| roundEnc(xmm23, 7); | |
| roundEnc(xmm12, 7); | |
| roundEnc(xmm13, 7); | |
| roundEnc(xmm14, 7); | |
| roundEnc(xmm15, 7); | |
| roundEnc(xmm16, 7); | |
| roundEnc(xmm17, 7); | |
| __ cmpl(rounds, 52); | |
| __ jcc(Assembler::aboveEqual, AES192); | |
| // Aesenclast round operation for keysize = 128 | |
| lastroundEnc(xmm24, 7); | |
| __ jmp(END_LOOP); | |
| //Additional 2 rounds of Aesenc operation for keysize = 192 | |
| __ bind(AES192); | |
| roundEnc(xmm24, 7); | |
| roundEnc(xmm19, 7); | |
| __ cmpl(rounds, 60); | |
| __ jcc(Assembler::aboveEqual, AES256); | |
| // Aesenclast round for keysize = 192 | |
| lastroundEnc(xmm20, 7); | |
| __ jmp(END_LOOP); | |
| // 2 rounds of Aesenc operation and Aesenclast for keysize = 256 | |
| __ bind(AES256); | |
| roundEnc(xmm20, 7); | |
| roundEnc(xmm21, 7); | |
| lastroundEnc(xmm22, 7); | |
| __ bind(END_LOOP); | |
| // Move 512 bytes of CT to destination | |
| __ evmovdquq(Address(dest_addr, pos, Address::times_1, 0 * 64), xmm0, Assembler::AVX_512bit); | |
| __ evmovdquq(Address(dest_addr, pos, Address::times_1, 1 * 64), xmm1, Assembler::AVX_512bit); | |
| __ evmovdquq(Address(dest_addr, pos, Address::times_1, 2 * 64), xmm2, Assembler::AVX_512bit); | |
| __ evmovdquq(Address(dest_addr, pos, Address::times_1, 3 * 64), xmm3, Assembler::AVX_512bit); | |
| __ evmovdquq(Address(dest_addr, pos, Address::times_1, 4 * 64), xmm4, Assembler::AVX_512bit); | |
| __ evmovdquq(Address(dest_addr, pos, Address::times_1, 5 * 64), xmm5, Assembler::AVX_512bit); | |
| __ evmovdquq(Address(dest_addr, pos, Address::times_1, 6 * 64), xmm6, Assembler::AVX_512bit); | |
| __ evmovdquq(Address(dest_addr, pos, Address::times_1, 7 * 64), xmm7, Assembler::AVX_512bit); | |
| __ addq(pos, 512); | |
| __ decq(len); | |
| __ jcc(Assembler::notEqual, LOOP); | |
| __ bind(REMAINDER); | |
| __ vzeroupper(); | |
| __ cmpq(rbx, 0); | |
| __ jcc(Assembler::equal, END); | |
| // Process 16 bytes at a time | |
| __ bind(LOOP2); | |
| __ movdqu(xmm1, Address(src_addr, pos, Address::times_1, 0)); | |
| __ vpxor(xmm1, xmm1, xmm8, Assembler::AVX_128bit); | |
| // xmm2 contains shuffled key for Aesenclast operation. | |
| __ vmovdqu(xmm2, xmm24); | |
| __ vaesenc(xmm1, xmm1, xmm9, Assembler::AVX_128bit); | |
| __ vaesenc(xmm1, xmm1, xmm10, Assembler::AVX_128bit); | |
| __ vaesenc(xmm1, xmm1, xmm23, Assembler::AVX_128bit); | |
| __ vaesenc(xmm1, xmm1, xmm12, Assembler::AVX_128bit); | |
| __ vaesenc(xmm1, xmm1, xmm13, Assembler::AVX_128bit); | |
| __ vaesenc(xmm1, xmm1, xmm14, Assembler::AVX_128bit); | |
| __ vaesenc(xmm1, xmm1, xmm15, Assembler::AVX_128bit); | |
| __ vaesenc(xmm1, xmm1, xmm16, Assembler::AVX_128bit); | |
| __ vaesenc(xmm1, xmm1, xmm17, Assembler::AVX_128bit); | |
| __ cmpl(rounds, 52); | |
| __ jcc(Assembler::below, LAST2); | |
| __ vmovdqu(xmm2, xmm20); | |
| __ vaesenc(xmm1, xmm1, xmm24, Assembler::AVX_128bit); | |
| __ vaesenc(xmm1, xmm1, xmm19, Assembler::AVX_128bit); | |
| __ cmpl(rounds, 60); | |
| __ jcc(Assembler::below, LAST2); | |
| __ vmovdqu(xmm2, xmm22); | |
| __ vaesenc(xmm1, xmm1, xmm20, Assembler::AVX_128bit); | |
| __ vaesenc(xmm1, xmm1, xmm21, Assembler::AVX_128bit); | |
| __ bind(LAST2); | |
| // Aesenclast round | |
| __ vaesenclast(xmm1, xmm1, xmm2, Assembler::AVX_128bit); | |
| // Write 16 bytes of CT to destination | |
| __ movdqu(Address(dest_addr, pos, Address::times_1, 0), xmm1); | |
| __ addq(pos, 16); | |
| __ decq(rbx); | |
| __ jcc(Assembler::notEqual, LOOP2); | |
| __ bind(END); | |
| // Zero out the round keys | |
| __ evpxorq(xmm8, xmm8, xmm8, Assembler::AVX_512bit); | |
| __ evpxorq(xmm9, xmm9, xmm9, Assembler::AVX_512bit); | |
| __ evpxorq(xmm10, xmm10, xmm10, Assembler::AVX_512bit); | |
| __ evpxorq(xmm23, xmm23, xmm23, Assembler::AVX_512bit); | |
| __ evpxorq(xmm12, xmm12, xmm12, Assembler::AVX_512bit); | |
| __ evpxorq(xmm13, xmm13, xmm13, Assembler::AVX_512bit); | |
| __ evpxorq(xmm14, xmm14, xmm14, Assembler::AVX_512bit); | |
| __ evpxorq(xmm15, xmm15, xmm15, Assembler::AVX_512bit); | |
| __ evpxorq(xmm16, xmm16, xmm16, Assembler::AVX_512bit); | |
| __ evpxorq(xmm17, xmm17, xmm17, Assembler::AVX_512bit); | |
| __ evpxorq(xmm24, xmm24, xmm24, Assembler::AVX_512bit); | |
| __ cmpl(rounds, 44); | |
| __ jcc(Assembler::belowEqual, EXIT); | |
| __ evpxorq(xmm19, xmm19, xmm19, Assembler::AVX_512bit); | |
| __ evpxorq(xmm20, xmm20, xmm20, Assembler::AVX_512bit); | |
| __ cmpl(rounds, 52); | |
| __ jcc(Assembler::belowEqual, EXIT); | |
| __ evpxorq(xmm21, xmm21, xmm21, Assembler::AVX_512bit); | |
| __ evpxorq(xmm22, xmm22, xmm22, Assembler::AVX_512bit); | |
| __ bind(EXIT); | |
| __ pop(rbx); | |
| __ pop(rax); // return length | |
| __ pop(r12); | |
| __ pop(r13); | |
| } | |
| // AES-ECB Decrypt Operation | |
| void StubGenerator::aesecb_decrypt(Register src_addr, Register dest_addr, Register key, Register len) { | |
| Label NO_PARTS, LOOP, Loop_start, LOOP2, AES192, END_LOOP, AES256, REMAINDER, LAST2, END, KEY_192, KEY_256, EXIT; | |
| const Register pos = rax; | |
| const Register rounds = r12; | |
| __ push(r13); | |
| __ push(r12); | |
| // For EVEX with VL and BW, provide a standard mask, VL = 128 will guide the merge | |
| // context for the registers used, where all instructions below are using 128-bit mode | |
| // On EVEX without VL and BW, these instructions will all be AVX. | |
| if (VM_Version::supports_avx512vlbw()) { | |
| __ movl(rax, 0xffff); | |
| __ kmovql(k1, rax); | |
| } | |
| __ push(len); // Save | |
| __ push(rbx); | |
| __ vzeroupper(); | |
| __ xorptr(pos, pos); | |
| // Calculate number of rounds i.e. based on key length(128, 192, 256):44 for 10-rounds, 52 for 12-rounds, 60 for 14-rounds | |
| __ movl(rounds, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); | |
| // Load Key shuf mask | |
| const XMMRegister xmm_key_shuf_mask = xmm31; // used temporarily to swap key bytes up front | |
| __ movdqu(xmm_key_shuf_mask, ExternalAddress(key_shuffle_mask_addr()), rbx /*rscratch*/); | |
| // Load and shuffle round keys. The java expanded key ordering is rotated one position in decryption. | |
| // So the first round key is loaded from 1*16 here and last round key is loaded from 0*16 | |
| ev_load_key(xmm9, key, 1 * 16, xmm_key_shuf_mask); | |
| ev_load_key(xmm10, key, 2 * 16, xmm_key_shuf_mask); | |
| ev_load_key(xmm11, key, 3 * 16, xmm_key_shuf_mask); | |
| ev_load_key(xmm12, key, 4 * 16, xmm_key_shuf_mask); | |
| ev_load_key(xmm13, key, 5 * 16, xmm_key_shuf_mask); | |
| ev_load_key(xmm14, key, 6 * 16, xmm_key_shuf_mask); | |
| ev_load_key(xmm15, key, 7 * 16, xmm_key_shuf_mask); | |
| ev_load_key(xmm16, key, 8 * 16, xmm_key_shuf_mask); | |
| ev_load_key(xmm17, key, 9 * 16, xmm_key_shuf_mask); | |
| ev_load_key(xmm18, key, 10 * 16, xmm_key_shuf_mask); | |
| ev_load_key(xmm27, key, 0 * 16, xmm_key_shuf_mask); | |
| __ cmpl(rounds, 52); | |
| __ jcc(Assembler::greaterEqual, KEY_192); | |
| __ jmp(Loop_start); | |
| __ bind(KEY_192); | |
| ev_load_key(xmm19, key, 11 * 16, xmm_key_shuf_mask); | |
| ev_load_key(xmm20, key, 12 * 16, xmm_key_shuf_mask); | |
| __ cmpl(rounds, 60); | |
| __ jcc(Assembler::equal, KEY_256); | |
| __ jmp(Loop_start); | |
| __ bind(KEY_256); | |
| ev_load_key(xmm21, key, 13 * 16, xmm_key_shuf_mask); | |
| ev_load_key(xmm22, key, 14 * 16, xmm_key_shuf_mask); | |
| __ bind(Loop_start); | |
| __ movq(rbx, len); | |
| // Convert input length to number of blocks | |
| __ shrq(len, 4); | |
| __ shlq(rbx, 60); | |
| __ jcc(Assembler::equal, NO_PARTS); | |
| __ addq(len, 1); | |
| // Check if number of blocks is greater than/ equal to 32 | |
| // If true, blocks then 512 bytes are processed at a time (code marked by label LOOP) | |
| // If not, 16 bytes are processed (code marked by label REMAINDER) | |
| __ bind(NO_PARTS); | |
| __ movq(rbx, len); | |
| __ shrq(len, 5); | |
| __ jcc(Assembler::equal, REMAINDER); | |
| __ movl(r13, len); | |
| // Compute number of blocks that will be processed as 512 bytes at a time | |
| // Subtract this from the total number of blocks, which will then be processed by REMAINDER loop. | |
| __ shlq(r13, 5); | |
| __ subq(rbx, r13); | |
| __ bind(LOOP); | |
| // Move 64 bytes of CT data into a zmm register, as a result 512 bytes of CT loaded in zmm0-7 | |
| __ evmovdquq(xmm0, Address(src_addr, pos, Address::times_1, 0 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(xmm1, Address(src_addr, pos, Address::times_1, 1 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(xmm2, Address(src_addr, pos, Address::times_1, 2 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(xmm3, Address(src_addr, pos, Address::times_1, 3 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(xmm4, Address(src_addr, pos, Address::times_1, 4 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(xmm5, Address(src_addr, pos, Address::times_1, 5 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(xmm6, Address(src_addr, pos, Address::times_1, 6 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(xmm7, Address(src_addr, pos, Address::times_1, 7 * 64), Assembler::AVX_512bit); | |
| // Xor with the first round key | |
| __ evpxorq(xmm0, xmm0, xmm9, Assembler::AVX_512bit); | |
| __ evpxorq(xmm1, xmm1, xmm9, Assembler::AVX_512bit); | |
| __ evpxorq(xmm2, xmm2, xmm9, Assembler::AVX_512bit); | |
| __ evpxorq(xmm3, xmm3, xmm9, Assembler::AVX_512bit); | |
| __ evpxorq(xmm4, xmm4, xmm9, Assembler::AVX_512bit); | |
| __ evpxorq(xmm5, xmm5, xmm9, Assembler::AVX_512bit); | |
| __ evpxorq(xmm6, xmm6, xmm9, Assembler::AVX_512bit); | |
| __ evpxorq(xmm7, xmm7, xmm9, Assembler::AVX_512bit); | |
| // 9 rounds of Aesdec | |
| roundDec(xmm10, 7); | |
| roundDec(xmm11, 7); | |
| roundDec(xmm12, 7); | |
| roundDec(xmm13, 7); | |
| roundDec(xmm14, 7); | |
| roundDec(xmm15, 7); | |
| roundDec(xmm16, 7); | |
| roundDec(xmm17, 7); | |
| roundDec(xmm18, 7); | |
| __ cmpl(rounds, 52); | |
| __ jcc(Assembler::aboveEqual, AES192); | |
| // Aesdeclast round for keysize = 128 | |
| lastroundDec(xmm27, 7); | |
| __ jmp(END_LOOP); | |
| __ bind(AES192); | |
| // 2 Additional rounds for keysize = 192 | |
| roundDec(xmm19, 7); | |
| roundDec(xmm20, 7); | |
| __ cmpl(rounds, 60); | |
| __ jcc(Assembler::aboveEqual, AES256); | |
| // Aesdeclast round for keysize = 192 | |
| lastroundDec(xmm27, 7); | |
| __ jmp(END_LOOP); | |
| __ bind(AES256); | |
| // 2 Additional rounds and Aesdeclast for keysize = 256 | |
| roundDec(xmm21, 7); | |
| roundDec(xmm22, 7); | |
| lastroundDec(xmm27, 7); | |
| __ bind(END_LOOP); | |
| // Write 512 bytes of PT to the destination | |
| __ evmovdquq(Address(dest_addr, pos, Address::times_1, 0 * 64), xmm0, Assembler::AVX_512bit); | |
| __ evmovdquq(Address(dest_addr, pos, Address::times_1, 1 * 64), xmm1, Assembler::AVX_512bit); | |
| __ evmovdquq(Address(dest_addr, pos, Address::times_1, 2 * 64), xmm2, Assembler::AVX_512bit); | |
| __ evmovdquq(Address(dest_addr, pos, Address::times_1, 3 * 64), xmm3, Assembler::AVX_512bit); | |
| __ evmovdquq(Address(dest_addr, pos, Address::times_1, 4 * 64), xmm4, Assembler::AVX_512bit); | |
| __ evmovdquq(Address(dest_addr, pos, Address::times_1, 5 * 64), xmm5, Assembler::AVX_512bit); | |
| __ evmovdquq(Address(dest_addr, pos, Address::times_1, 6 * 64), xmm6, Assembler::AVX_512bit); | |
| __ evmovdquq(Address(dest_addr, pos, Address::times_1, 7 * 64), xmm7, Assembler::AVX_512bit); | |
| __ addq(pos, 512); | |
| __ decq(len); | |
| __ jcc(Assembler::notEqual, LOOP); | |
| __ bind(REMAINDER); | |
| __ vzeroupper(); | |
| __ cmpq(rbx, 0); | |
| __ jcc(Assembler::equal, END); | |
| // Process 16 bytes at a time | |
| __ bind(LOOP2); | |
| __ movdqu(xmm1, Address(src_addr, pos, Address::times_1, 0)); | |
| __ vpxor(xmm1, xmm1, xmm9, Assembler::AVX_128bit); | |
| // xmm2 contains shuffled key for Aesdeclast operation. | |
| __ vmovdqu(xmm2, xmm27); | |
| __ vaesdec(xmm1, xmm1, xmm10, Assembler::AVX_128bit); | |
| __ vaesdec(xmm1, xmm1, xmm11, Assembler::AVX_128bit); | |
| __ vaesdec(xmm1, xmm1, xmm12, Assembler::AVX_128bit); | |
| __ vaesdec(xmm1, xmm1, xmm13, Assembler::AVX_128bit); | |
| __ vaesdec(xmm1, xmm1, xmm14, Assembler::AVX_128bit); | |
| __ vaesdec(xmm1, xmm1, xmm15, Assembler::AVX_128bit); | |
| __ vaesdec(xmm1, xmm1, xmm16, Assembler::AVX_128bit); | |
| __ vaesdec(xmm1, xmm1, xmm17, Assembler::AVX_128bit); | |
| __ vaesdec(xmm1, xmm1, xmm18, Assembler::AVX_128bit); | |
| __ cmpl(rounds, 52); | |
| __ jcc(Assembler::below, LAST2); | |
| __ vaesdec(xmm1, xmm1, xmm19, Assembler::AVX_128bit); | |
| __ vaesdec(xmm1, xmm1, xmm20, Assembler::AVX_128bit); | |
| __ cmpl(rounds, 60); | |
| __ jcc(Assembler::below, LAST2); | |
| __ vaesdec(xmm1, xmm1, xmm21, Assembler::AVX_128bit); | |
| __ vaesdec(xmm1, xmm1, xmm22, Assembler::AVX_128bit); | |
| __ bind(LAST2); | |
| // Aesdeclast round | |
| __ vaesdeclast(xmm1, xmm1, xmm2, Assembler::AVX_128bit); | |
| // Write 16 bytes of PT to destination | |
| __ movdqu(Address(dest_addr, pos, Address::times_1, 0), xmm1); | |
| __ addq(pos, 16); | |
| __ decq(rbx); | |
| __ jcc(Assembler::notEqual, LOOP2); | |
| __ bind(END); | |
| // Zero out the round keys | |
| __ evpxorq(xmm8, xmm8, xmm8, Assembler::AVX_512bit); | |
| __ evpxorq(xmm9, xmm9, xmm9, Assembler::AVX_512bit); | |
| __ evpxorq(xmm10, xmm10, xmm10, Assembler::AVX_512bit); | |
| __ evpxorq(xmm11, xmm11, xmm11, Assembler::AVX_512bit); | |
| __ evpxorq(xmm12, xmm12, xmm12, Assembler::AVX_512bit); | |
| __ evpxorq(xmm13, xmm13, xmm13, Assembler::AVX_512bit); | |
| __ evpxorq(xmm14, xmm14, xmm14, Assembler::AVX_512bit); | |
| __ evpxorq(xmm15, xmm15, xmm15, Assembler::AVX_512bit); | |
| __ evpxorq(xmm16, xmm16, xmm16, Assembler::AVX_512bit); | |
| __ evpxorq(xmm17, xmm17, xmm17, Assembler::AVX_512bit); | |
| __ evpxorq(xmm18, xmm18, xmm18, Assembler::AVX_512bit); | |
| __ evpxorq(xmm27, xmm27, xmm27, Assembler::AVX_512bit); | |
| __ cmpl(rounds, 44); | |
| __ jcc(Assembler::belowEqual, EXIT); | |
| __ evpxorq(xmm19, xmm19, xmm19, Assembler::AVX_512bit); | |
| __ evpxorq(xmm20, xmm20, xmm20, Assembler::AVX_512bit); | |
| __ cmpl(rounds, 52); | |
| __ jcc(Assembler::belowEqual, EXIT); | |
| __ evpxorq(xmm21, xmm21, xmm21, Assembler::AVX_512bit); | |
| __ evpxorq(xmm22, xmm22, xmm22, Assembler::AVX_512bit); | |
| __ bind(EXIT); | |
| __ pop(rbx); | |
| __ pop(rax); // return length | |
| __ pop(r12); | |
| __ pop(r13); | |
| } | |
| // AES Counter Mode using VAES instructions | |
| void StubGenerator::aesctr_encrypt(Register src_addr, Register dest_addr, Register key, Register counter, | |
| Register len_reg, Register used, Register used_addr, Register saved_encCounter_start) { | |
| const Register rounds = rax; | |
| const Register pos = r12; | |
| const Register tail = r15; | |
| Label PRELOOP_START, EXIT_PRELOOP, REMAINDER, REMAINDER_16, LOOP, END, EXIT, END_LOOP, | |
| AES192, AES256, AES192_REMAINDER16, REMAINDER16_END_LOOP, AES256_REMAINDER16, | |
| REMAINDER_8, REMAINDER_4, AES192_REMAINDER8, REMAINDER_LOOP, AES256_REMINDER, | |
| AES192_REMAINDER, END_REMAINDER_LOOP, AES256_REMAINDER8, REMAINDER8_END_LOOP, | |
| AES192_REMAINDER4, AES256_REMAINDER4, AES256_REMAINDER, END_REMAINDER4, EXTRACT_TAILBYTES, | |
| EXTRACT_TAIL_4BYTES, EXTRACT_TAIL_2BYTES, EXTRACT_TAIL_1BYTE, STORE_CTR; | |
| __ cmpl(len_reg, 0); | |
| __ jcc(Assembler::belowEqual, EXIT); | |
| __ movl(pos, 0); | |
| // if the number of used encrypted counter bytes < 16, | |
| // XOR PT with saved encrypted counter to obtain CT | |
| __ bind(PRELOOP_START); | |
| __ cmpl(used, 16); | |
| __ jcc(Assembler::aboveEqual, EXIT_PRELOOP); | |
| __ movb(rbx, Address(saved_encCounter_start, used)); | |
| __ xorb(rbx, Address(src_addr, pos)); | |
| __ movb(Address(dest_addr, pos), rbx); | |
| __ addptr(pos, 1); | |
| __ addptr(used, 1); | |
| __ decrement(len_reg); | |
| __ jcc(Assembler::notEqual, PRELOOP_START); | |
| __ bind(EXIT_PRELOOP); | |
| __ movl(Address(used_addr, 0), used); | |
| __ cmpl(len_reg, 0); | |
| __ jcc(Assembler::equal, EXIT); | |
| // Calculate number of rounds i.e. 10, 12, 14, based on key length(128, 192, 256). | |
| __ movl(rounds, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); | |
| __ vpxor(xmm0, xmm0, xmm0, Assembler::AVX_128bit); | |
| // Move initial counter value in xmm0 | |
| __ movdqu(xmm0, Address(counter, 0)); | |
| // broadcast counter value to zmm8 | |
| __ evshufi64x2(xmm8, xmm0, xmm0, 0, Assembler::AVX_512bit); | |
| // load lbswap mask | |
| __ evmovdquq(xmm16, ExternalAddress(counter_shuffle_mask_addr()), Assembler::AVX_512bit, r15 /*rscratch*/); | |
| //shuffle counter using lbswap_mask | |
| __ vpshufb(xmm8, xmm8, xmm16, Assembler::AVX_512bit); | |
| // pre-increment and propagate counter values to zmm9-zmm15 registers. | |
| // Linc0 increments the zmm8 by 1 (initial value being 0), Linc4 increments the counters zmm9-zmm15 by 4 | |
| // The counter is incremented after each block i.e. 16 bytes is processed; | |
| // each zmm register has 4 counter values as its MSB | |
| // the counters are incremented in parallel | |
| const XMMRegister ones = xmm17; | |
| // Vector value to propagate carries | |
| __ evmovdquq(ones, ExternalAddress(counter_mask_ones_addr()), Assembler::AVX_512bit, r15); | |
| __ evmovdquq(xmm19, ExternalAddress(counter_mask_linc0_addr()), Assembler::AVX_512bit, r15 /*rscratch*/); | |
| ev_add128(xmm8, xmm8, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); | |
| __ evmovdquq(xmm19, ExternalAddress(counter_mask_linc4_addr()), Assembler::AVX_512bit, r15 /*rscratch*/); | |
| ev_add128(xmm9, xmm8, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); | |
| ev_add128(xmm10, xmm9, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); | |
| ev_add128(xmm11, xmm10, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); | |
| ev_add128(xmm12, xmm11, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); | |
| ev_add128(xmm13, xmm12, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); | |
| ev_add128(xmm14, xmm13, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); | |
| ev_add128(xmm15, xmm14, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); | |
| // load linc32 mask in zmm register.linc32 increments counter by 32 | |
| __ evmovdquq(xmm19, ExternalAddress(counter_mask_linc32_addr()), Assembler::AVX_512bit, r15 /*rscratch*/); | |
| // xmm31 contains the key shuffle mask. | |
| __ movdqu(xmm31, ExternalAddress(key_shuffle_mask_addr()), r15 /*rscratch*/); | |
| // Load key function loads 128 bit key and shuffles it. Then we broadcast the shuffled key to convert it into a 512 bit value. | |
| // For broadcasting the values to ZMM, vshufi64 is used instead of evbroadcasti64x2 as the source in this case is ZMM register | |
| // that holds shuffled key value. | |
| ev_load_key(xmm20, key, 0, xmm31); | |
| ev_load_key(xmm21, key, 1 * 16, xmm31); | |
| ev_load_key(xmm22, key, 2 * 16, xmm31); | |
| ev_load_key(xmm23, key, 3 * 16, xmm31); | |
| ev_load_key(xmm24, key, 4 * 16, xmm31); | |
| ev_load_key(xmm25, key, 5 * 16, xmm31); | |
| ev_load_key(xmm26, key, 6 * 16, xmm31); | |
| ev_load_key(xmm27, key, 7 * 16, xmm31); | |
| ev_load_key(xmm28, key, 8 * 16, xmm31); | |
| ev_load_key(xmm29, key, 9 * 16, xmm31); | |
| ev_load_key(xmm30, key, 10 * 16, xmm31); | |
| // Process 32 blocks or 512 bytes of data | |
| __ bind(LOOP); | |
| __ cmpl(len_reg, 512); | |
| __ jcc(Assembler::less, REMAINDER); | |
| __ subq(len_reg, 512); | |
| //Shuffle counter and Exor it with roundkey1. Result is stored in zmm0-7 | |
| __ vpshufb(xmm0, xmm8, xmm16, Assembler::AVX_512bit); | |
| __ evpxorq(xmm0, xmm0, xmm20, Assembler::AVX_512bit); | |
| __ vpshufb(xmm1, xmm9, xmm16, Assembler::AVX_512bit); | |
| __ evpxorq(xmm1, xmm1, xmm20, Assembler::AVX_512bit); | |
| __ vpshufb(xmm2, xmm10, xmm16, Assembler::AVX_512bit); | |
| __ evpxorq(xmm2, xmm2, xmm20, Assembler::AVX_512bit); | |
| __ vpshufb(xmm3, xmm11, xmm16, Assembler::AVX_512bit); | |
| __ evpxorq(xmm3, xmm3, xmm20, Assembler::AVX_512bit); | |
| __ vpshufb(xmm4, xmm12, xmm16, Assembler::AVX_512bit); | |
| __ evpxorq(xmm4, xmm4, xmm20, Assembler::AVX_512bit); | |
| __ vpshufb(xmm5, xmm13, xmm16, Assembler::AVX_512bit); | |
| __ evpxorq(xmm5, xmm5, xmm20, Assembler::AVX_512bit); | |
| __ vpshufb(xmm6, xmm14, xmm16, Assembler::AVX_512bit); | |
| __ evpxorq(xmm6, xmm6, xmm20, Assembler::AVX_512bit); | |
| __ vpshufb(xmm7, xmm15, xmm16, Assembler::AVX_512bit); | |
| __ evpxorq(xmm7, xmm7, xmm20, Assembler::AVX_512bit); | |
| // Perform AES encode operations and put results in zmm0-zmm7. | |
| // This is followed by incrementing counter values in zmm8-zmm15. | |
| // Since we will be processing 32 blocks at a time, the counter is incremented by 32. | |
| roundEnc(xmm21, 7); | |
| ev_add128(xmm8, xmm8, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); | |
| roundEnc(xmm22, 7); | |
| ev_add128(xmm9, xmm9, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); | |
| roundEnc(xmm23, 7); | |
| ev_add128(xmm10, xmm10, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); | |
| roundEnc(xmm24, 7); | |
| ev_add128(xmm11, xmm11, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); | |
| roundEnc(xmm25, 7); | |
| ev_add128(xmm12, xmm12, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); | |
| roundEnc(xmm26, 7); | |
| ev_add128(xmm13, xmm13, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); | |
| roundEnc(xmm27, 7); | |
| ev_add128(xmm14, xmm14, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); | |
| roundEnc(xmm28, 7); | |
| ev_add128(xmm15, xmm15, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); | |
| roundEnc(xmm29, 7); | |
| __ cmpl(rounds, 52); | |
| __ jcc(Assembler::aboveEqual, AES192); | |
| lastroundEnc(xmm30, 7); | |
| __ jmp(END_LOOP); | |
| __ bind(AES192); | |
| roundEnc(xmm30, 7); | |
| ev_load_key(xmm18, key, 11 * 16, xmm31); | |
| roundEnc(xmm18, 7); | |
| __ cmpl(rounds, 60); | |
| __ jcc(Assembler::aboveEqual, AES256); | |
| ev_load_key(xmm18, key, 12 * 16, xmm31); | |
| lastroundEnc(xmm18, 7); | |
| __ jmp(END_LOOP); | |
| __ bind(AES256); | |
| ev_load_key(xmm18, key, 12 * 16, xmm31); | |
| roundEnc(xmm18, 7); | |
| ev_load_key(xmm18, key, 13 * 16, xmm31); | |
| roundEnc(xmm18, 7); | |
| ev_load_key(xmm18, key, 14 * 16, xmm31); | |
| lastroundEnc(xmm18, 7); | |
| // After AES encode rounds, the encrypted block cipher lies in zmm0-zmm7 | |
| // xor encrypted block cipher and input plaintext and store resultant ciphertext | |
| __ bind(END_LOOP); | |
| __ evpxorq(xmm0, xmm0, Address(src_addr, pos, Address::times_1, 0 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(Address(dest_addr, pos, Address::times_1, 0), xmm0, Assembler::AVX_512bit); | |
| __ evpxorq(xmm1, xmm1, Address(src_addr, pos, Address::times_1, 1 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(Address(dest_addr, pos, Address::times_1, 64), xmm1, Assembler::AVX_512bit); | |
| __ evpxorq(xmm2, xmm2, Address(src_addr, pos, Address::times_1, 2 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(Address(dest_addr, pos, Address::times_1, 2 * 64), xmm2, Assembler::AVX_512bit); | |
| __ evpxorq(xmm3, xmm3, Address(src_addr, pos, Address::times_1, 3 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(Address(dest_addr, pos, Address::times_1, 3 * 64), xmm3, Assembler::AVX_512bit); | |
| __ evpxorq(xmm4, xmm4, Address(src_addr, pos, Address::times_1, 4 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(Address(dest_addr, pos, Address::times_1, 4 * 64), xmm4, Assembler::AVX_512bit); | |
| __ evpxorq(xmm5, xmm5, Address(src_addr, pos, Address::times_1, 5 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(Address(dest_addr, pos, Address::times_1, 5 * 64), xmm5, Assembler::AVX_512bit); | |
| __ evpxorq(xmm6, xmm6, Address(src_addr, pos, Address::times_1, 6 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(Address(dest_addr, pos, Address::times_1, 6 * 64), xmm6, Assembler::AVX_512bit); | |
| __ evpxorq(xmm7, xmm7, Address(src_addr, pos, Address::times_1, 7 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(Address(dest_addr, pos, Address::times_1, 7 * 64), xmm7, Assembler::AVX_512bit); | |
| __ addq(pos, 512); | |
| __ jmp(LOOP); | |
| // Encode 256, 128, 64 or 16 bytes at a time if length is less than 512 bytes | |
| __ bind(REMAINDER); | |
| __ cmpl(len_reg, 0); | |
| __ jcc(Assembler::equal, END); | |
| __ cmpl(len_reg, 256); | |
| __ jcc(Assembler::aboveEqual, REMAINDER_16); | |
| __ cmpl(len_reg, 128); | |
| __ jcc(Assembler::aboveEqual, REMAINDER_8); | |
| __ cmpl(len_reg, 64); | |
| __ jcc(Assembler::aboveEqual, REMAINDER_4); | |
| // At this point, we will process 16 bytes of data at a time. | |
| // So load xmm19 with counter increment value as 1 | |
| __ evmovdquq(xmm19, ExternalAddress(counter_mask_linc1_addr()), Assembler::AVX_128bit, r15 /*rscratch*/); | |
| __ jmp(REMAINDER_LOOP); | |
| // Each ZMM register can be used to encode 64 bytes of data, so we have 4 ZMM registers to encode 256 bytes of data | |
| __ bind(REMAINDER_16); | |
| __ subq(len_reg, 256); | |
| // As we process 16 blocks at a time, load mask for incrementing the counter value by 16 | |
| __ evmovdquq(xmm19, ExternalAddress(counter_mask_linc16_addr()), Assembler::AVX_512bit, r15 /*rscratch*/); | |
| // shuffle counter and XOR counter with roundkey1 | |
| __ vpshufb(xmm0, xmm8, xmm16, Assembler::AVX_512bit); | |
| __ evpxorq(xmm0, xmm0, xmm20, Assembler::AVX_512bit); | |
| __ vpshufb(xmm1, xmm9, xmm16, Assembler::AVX_512bit); | |
| __ evpxorq(xmm1, xmm1, xmm20, Assembler::AVX_512bit); | |
| __ vpshufb(xmm2, xmm10, xmm16, Assembler::AVX_512bit); | |
| __ evpxorq(xmm2, xmm2, xmm20, Assembler::AVX_512bit); | |
| __ vpshufb(xmm3, xmm11, xmm16, Assembler::AVX_512bit); | |
| __ evpxorq(xmm3, xmm3, xmm20, Assembler::AVX_512bit); | |
| // Increment counter values by 16 | |
| ev_add128(xmm8, xmm8, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); | |
| ev_add128(xmm9, xmm9, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); | |
| // AES encode rounds | |
| roundEnc(xmm21, 3); | |
| roundEnc(xmm22, 3); | |
| roundEnc(xmm23, 3); | |
| roundEnc(xmm24, 3); | |
| roundEnc(xmm25, 3); | |
| roundEnc(xmm26, 3); | |
| roundEnc(xmm27, 3); | |
| roundEnc(xmm28, 3); | |
| roundEnc(xmm29, 3); | |
| __ cmpl(rounds, 52); | |
| __ jcc(Assembler::aboveEqual, AES192_REMAINDER16); | |
| lastroundEnc(xmm30, 3); | |
| __ jmp(REMAINDER16_END_LOOP); | |
| __ bind(AES192_REMAINDER16); | |
| roundEnc(xmm30, 3); | |
| ev_load_key(xmm18, key, 11 * 16, xmm31); | |
| roundEnc(xmm18, 3); | |
| ev_load_key(xmm5, key, 12 * 16, xmm31); | |
| __ cmpl(rounds, 60); | |
| __ jcc(Assembler::aboveEqual, AES256_REMAINDER16); | |
| lastroundEnc(xmm5, 3); | |
| __ jmp(REMAINDER16_END_LOOP); | |
| __ bind(AES256_REMAINDER16); | |
| roundEnc(xmm5, 3); | |
| ev_load_key(xmm6, key, 13 * 16, xmm31); | |
| roundEnc(xmm6, 3); | |
| ev_load_key(xmm7, key, 14 * 16, xmm31); | |
| lastroundEnc(xmm7, 3); | |
| // After AES encode rounds, the encrypted block cipher lies in zmm0-zmm3 | |
| // xor 256 bytes of PT with the encrypted counters to produce CT. | |
| __ bind(REMAINDER16_END_LOOP); | |
| __ evpxorq(xmm0, xmm0, Address(src_addr, pos, Address::times_1, 0), Assembler::AVX_512bit); | |
| __ evmovdquq(Address(dest_addr, pos, Address::times_1, 0), xmm0, Assembler::AVX_512bit); | |
| __ evpxorq(xmm1, xmm1, Address(src_addr, pos, Address::times_1, 1 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(Address(dest_addr, pos, Address::times_1, 1 * 64), xmm1, Assembler::AVX_512bit); | |
| __ evpxorq(xmm2, xmm2, Address(src_addr, pos, Address::times_1, 2 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(Address(dest_addr, pos, Address::times_1, 2 * 64), xmm2, Assembler::AVX_512bit); | |
| __ evpxorq(xmm3, xmm3, Address(src_addr, pos, Address::times_1, 3 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(Address(dest_addr, pos, Address::times_1, 3 * 64), xmm3, Assembler::AVX_512bit); | |
| __ addq(pos, 256); | |
| __ cmpl(len_reg, 128); | |
| __ jcc(Assembler::aboveEqual, REMAINDER_8); | |
| __ cmpl(len_reg, 64); | |
| __ jcc(Assembler::aboveEqual, REMAINDER_4); | |
| //load mask for incrementing the counter value by 1 | |
| __ evmovdquq(xmm19, ExternalAddress(counter_mask_linc1_addr()), Assembler::AVX_128bit, r15 /*rscratch*/); | |
| __ jmp(REMAINDER_LOOP); | |
| // Each ZMM register can be used to encode 64 bytes of data, so we have 2 ZMM registers to encode 128 bytes of data | |
| __ bind(REMAINDER_8); | |
| __ subq(len_reg, 128); | |
| // As we process 8 blocks at a time, load mask for incrementing the counter value by 8 | |
| __ evmovdquq(xmm19, ExternalAddress(counter_mask_linc8_addr()), Assembler::AVX_512bit, r15 /*rscratch*/); | |
| // shuffle counters and xor with roundkey1 | |
| __ vpshufb(xmm0, xmm8, xmm16, Assembler::AVX_512bit); | |
| __ evpxorq(xmm0, xmm0, xmm20, Assembler::AVX_512bit); | |
| __ vpshufb(xmm1, xmm9, xmm16, Assembler::AVX_512bit); | |
| __ evpxorq(xmm1, xmm1, xmm20, Assembler::AVX_512bit); | |
| // increment counter by 8 | |
| ev_add128(xmm8, xmm8, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); | |
| // AES encode | |
| roundEnc(xmm21, 1); | |
| roundEnc(xmm22, 1); | |
| roundEnc(xmm23, 1); | |
| roundEnc(xmm24, 1); | |
| roundEnc(xmm25, 1); | |
| roundEnc(xmm26, 1); | |
| roundEnc(xmm27, 1); | |
| roundEnc(xmm28, 1); | |
| roundEnc(xmm29, 1); | |
| __ cmpl(rounds, 52); | |
| __ jcc(Assembler::aboveEqual, AES192_REMAINDER8); | |
| lastroundEnc(xmm30, 1); | |
| __ jmp(REMAINDER8_END_LOOP); | |
| __ bind(AES192_REMAINDER8); | |
| roundEnc(xmm30, 1); | |
| ev_load_key(xmm18, key, 11 * 16, xmm31); | |
| roundEnc(xmm18, 1); | |
| ev_load_key(xmm5, key, 12 * 16, xmm31); | |
| __ cmpl(rounds, 60); | |
| __ jcc(Assembler::aboveEqual, AES256_REMAINDER8); | |
| lastroundEnc(xmm5, 1); | |
| __ jmp(REMAINDER8_END_LOOP); | |
| __ bind(AES256_REMAINDER8); | |
| roundEnc(xmm5, 1); | |
| ev_load_key(xmm6, key, 13 * 16, xmm31); | |
| roundEnc(xmm6, 1); | |
| ev_load_key(xmm7, key, 14 * 16, xmm31); | |
| lastroundEnc(xmm7, 1); | |
| __ bind(REMAINDER8_END_LOOP); | |
| // After AES encode rounds, the encrypted block cipher lies in zmm0-zmm1 | |
| // XOR PT with the encrypted counter and store as CT | |
| __ evpxorq(xmm0, xmm0, Address(src_addr, pos, Address::times_1, 0 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(Address(dest_addr, pos, Address::times_1, 0 * 64), xmm0, Assembler::AVX_512bit); | |
| __ evpxorq(xmm1, xmm1, Address(src_addr, pos, Address::times_1, 1 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(Address(dest_addr, pos, Address::times_1, 1 * 64), xmm1, Assembler::AVX_512bit); | |
| __ addq(pos, 128); | |
| __ cmpl(len_reg, 64); | |
| __ jcc(Assembler::aboveEqual, REMAINDER_4); | |
| // load mask for incrementing the counter value by 1 | |
| __ evmovdquq(xmm19, ExternalAddress(counter_mask_linc1_addr()), Assembler::AVX_128bit, r15 /*rscratch*/); | |
| __ jmp(REMAINDER_LOOP); | |
| // Each ZMM register can be used to encode 64 bytes of data, so we have 1 ZMM register used in this block of code | |
| __ bind(REMAINDER_4); | |
| __ subq(len_reg, 64); | |
| // As we process 4 blocks at a time, load mask for incrementing the counter value by 4 | |
| __ evmovdquq(xmm19, ExternalAddress(counter_mask_linc4_addr()), Assembler::AVX_512bit, r15 /*rscratch*/); | |
| // XOR counter with first roundkey | |
| __ vpshufb(xmm0, xmm8, xmm16, Assembler::AVX_512bit); | |
| __ evpxorq(xmm0, xmm0, xmm20, Assembler::AVX_512bit); | |
| // Increment counter | |
| ev_add128(xmm8, xmm8, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); | |
| __ vaesenc(xmm0, xmm0, xmm21, Assembler::AVX_512bit); | |
| __ vaesenc(xmm0, xmm0, xmm22, Assembler::AVX_512bit); | |
| __ vaesenc(xmm0, xmm0, xmm23, Assembler::AVX_512bit); | |
| __ vaesenc(xmm0, xmm0, xmm24, Assembler::AVX_512bit); | |
| __ vaesenc(xmm0, xmm0, xmm25, Assembler::AVX_512bit); | |
| __ vaesenc(xmm0, xmm0, xmm26, Assembler::AVX_512bit); | |
| __ vaesenc(xmm0, xmm0, xmm27, Assembler::AVX_512bit); | |
| __ vaesenc(xmm0, xmm0, xmm28, Assembler::AVX_512bit); | |
| __ vaesenc(xmm0, xmm0, xmm29, Assembler::AVX_512bit); | |
| __ cmpl(rounds, 52); | |
| __ jcc(Assembler::aboveEqual, AES192_REMAINDER4); | |
| __ vaesenclast(xmm0, xmm0, xmm30, Assembler::AVX_512bit); | |
| __ jmp(END_REMAINDER4); | |
| __ bind(AES192_REMAINDER4); | |
| __ vaesenc(xmm0, xmm0, xmm30, Assembler::AVX_512bit); | |
| ev_load_key(xmm18, key, 11 * 16, xmm31); | |
| __ vaesenc(xmm0, xmm0, xmm18, Assembler::AVX_512bit); | |
| ev_load_key(xmm5, key, 12 * 16, xmm31); | |
| __ cmpl(rounds, 60); | |
| __ jcc(Assembler::aboveEqual, AES256_REMAINDER4); | |
| __ vaesenclast(xmm0, xmm0, xmm5, Assembler::AVX_512bit); | |
| __ jmp(END_REMAINDER4); | |
| __ bind(AES256_REMAINDER4); | |
| __ vaesenc(xmm0, xmm0, xmm5, Assembler::AVX_512bit); | |
| ev_load_key(xmm6, key, 13 * 16, xmm31); | |
| __ vaesenc(xmm0, xmm0, xmm6, Assembler::AVX_512bit); | |
| ev_load_key(xmm7, key, 14 * 16, xmm31); | |
| __ vaesenclast(xmm0, xmm0, xmm7, Assembler::AVX_512bit); | |
| // After AES encode rounds, the encrypted block cipher lies in zmm0. | |
| // XOR encrypted block cipher with PT and store 64 bytes of ciphertext | |
| __ bind(END_REMAINDER4); | |
| __ evpxorq(xmm0, xmm0, Address(src_addr, pos, Address::times_1, 0 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(Address(dest_addr, pos, Address::times_1, 0), xmm0, Assembler::AVX_512bit); | |
| __ addq(pos, 64); | |
| // load mask for incrementing the counter value by 1 | |
| __ evmovdquq(xmm19, ExternalAddress(counter_mask_linc1_addr()), Assembler::AVX_128bit, r15 /*rscratch*/); | |
| // For a single block, the AES rounds start here. | |
| __ bind(REMAINDER_LOOP); | |
| __ cmpl(len_reg, 0); | |
| __ jcc(Assembler::belowEqual, END); | |
| // XOR counter with first roundkey | |
| __ vpshufb(xmm0, xmm8, xmm16, Assembler::AVX_128bit); | |
| __ evpxorq(xmm0, xmm0, xmm20, Assembler::AVX_128bit); | |
| __ vaesenc(xmm0, xmm0, xmm21, Assembler::AVX_128bit); | |
| // Increment counter by 1 | |
| ev_add128(xmm8, xmm8, xmm19, Assembler::AVX_128bit, /*ktmp*/k1, ones); | |
| __ vaesenc(xmm0, xmm0, xmm22, Assembler::AVX_128bit); | |
| __ vaesenc(xmm0, xmm0, xmm23, Assembler::AVX_128bit); | |
| __ vaesenc(xmm0, xmm0, xmm24, Assembler::AVX_128bit); | |
| __ vaesenc(xmm0, xmm0, xmm25, Assembler::AVX_128bit); | |
| __ vaesenc(xmm0, xmm0, xmm26, Assembler::AVX_128bit); | |
| __ vaesenc(xmm0, xmm0, xmm27, Assembler::AVX_128bit); | |
| __ vaesenc(xmm0, xmm0, xmm28, Assembler::AVX_128bit); | |
| __ vaesenc(xmm0, xmm0, xmm29, Assembler::AVX_128bit); | |
| __ cmpl(rounds, 52); | |
| __ jcc(Assembler::aboveEqual, AES192_REMAINDER); | |
| __ vaesenclast(xmm0, xmm0, xmm30, Assembler::AVX_128bit); | |
| __ jmp(END_REMAINDER_LOOP); | |
| __ bind(AES192_REMAINDER); | |
| __ vaesenc(xmm0, xmm0, xmm30, Assembler::AVX_128bit); | |
| ev_load_key(xmm18, key, 11 * 16, xmm31); | |
| __ vaesenc(xmm0, xmm0, xmm18, Assembler::AVX_128bit); | |
| ev_load_key(xmm5, key, 12 * 16, xmm31); | |
| __ cmpl(rounds, 60); | |
| __ jcc(Assembler::aboveEqual, AES256_REMAINDER); | |
| __ vaesenclast(xmm0, xmm0, xmm5, Assembler::AVX_128bit); | |
| __ jmp(END_REMAINDER_LOOP); | |
| __ bind(AES256_REMAINDER); | |
| __ vaesenc(xmm0, xmm0, xmm5, Assembler::AVX_128bit); | |
| ev_load_key(xmm6, key, 13 * 16, xmm31); | |
| __ vaesenc(xmm0, xmm0, xmm6, Assembler::AVX_128bit); | |
| ev_load_key(xmm7, key, 14 * 16, xmm31); | |
| __ vaesenclast(xmm0, xmm0, xmm7, Assembler::AVX_128bit); | |
| __ bind(END_REMAINDER_LOOP); | |
| // If the length register is less than the blockSize i.e. 16 | |
| // then we store only those bytes of the CT to the destination | |
| // corresponding to the length register value | |
| // extracting the exact number of bytes is handled by EXTRACT_TAILBYTES | |
| __ cmpl(len_reg, 16); | |
| __ jcc(Assembler::less, EXTRACT_TAILBYTES); | |
| __ subl(len_reg, 16); | |
| // After AES encode rounds, the encrypted block cipher lies in xmm0. | |
| // If the length register is equal to 16 bytes, store CT in dest after XOR operation. | |
| __ evpxorq(xmm0, xmm0, Address(src_addr, pos, Address::times_1, 0), Assembler::AVX_128bit); | |
| __ evmovdquq(Address(dest_addr, pos, Address::times_1, 0), xmm0, Assembler::AVX_128bit); | |
| __ addl(pos, 16); | |
| __ jmp(REMAINDER_LOOP); | |
| __ bind(EXTRACT_TAILBYTES); | |
| // Save encrypted counter value in xmm0 for next invocation, before XOR operation | |
| __ movdqu(Address(saved_encCounter_start, 0), xmm0); | |
| // XOR encryted block cipher in xmm0 with PT to produce CT | |
| // extract up to 15 bytes of CT from xmm0 as specified by length register | |
| __ testptr(len_reg, 8); | |
| __ jcc(Assembler::zero, EXTRACT_TAIL_4BYTES); | |
| __ pextrq(tail, xmm0, 0); | |
| __ xorq(tail, Address(src_addr, pos, Address::times_1, 0)); | |
| __ movq(Address(dest_addr, pos), tail); | |
| __ psrldq(xmm0, 8); | |
| __ addl(pos, 8); | |
| __ bind(EXTRACT_TAIL_4BYTES); | |
| __ testptr(len_reg, 4); | |
| __ jcc(Assembler::zero, EXTRACT_TAIL_2BYTES); | |
| __ pextrd(tail, xmm0, 0); | |
| __ xorl(tail, Address(src_addr, pos, Address::times_1, 0)); | |
| __ movl(Address(dest_addr, pos), tail); | |
| __ psrldq(xmm0, 4); | |
| __ addq(pos, 4); | |
| __ bind(EXTRACT_TAIL_2BYTES); | |
| __ testptr(len_reg, 2); | |
| __ jcc(Assembler::zero, EXTRACT_TAIL_1BYTE); | |
| __ pextrw(tail, xmm0, 0); | |
| __ xorw(tail, Address(src_addr, pos, Address::times_1, 0)); | |
| __ movw(Address(dest_addr, pos), tail); | |
| __ psrldq(xmm0, 2); | |
| __ addl(pos, 2); | |
| __ bind(EXTRACT_TAIL_1BYTE); | |
| __ testptr(len_reg, 1); | |
| __ jcc(Assembler::zero, END); | |
| __ pextrb(tail, xmm0, 0); | |
| __ xorb(tail, Address(src_addr, pos, Address::times_1, 0)); | |
| __ movb(Address(dest_addr, pos), tail); | |
| __ addl(pos, 1); | |
| __ bind(END); | |
| // If there are no tail bytes, store counter value and exit | |
| __ cmpl(len_reg, 0); | |
| __ jcc(Assembler::equal, STORE_CTR); | |
| __ movl(Address(used_addr, 0), len_reg); | |
| __ bind(STORE_CTR); | |
| //shuffle updated counter and store it | |
| __ vpshufb(xmm8, xmm8, xmm16, Assembler::AVX_128bit); | |
| __ movdqu(Address(counter, 0), xmm8); | |
| // Zero out counter and key registers | |
| __ evpxorq(xmm8, xmm8, xmm8, Assembler::AVX_512bit); | |
| __ evpxorq(xmm20, xmm20, xmm20, Assembler::AVX_512bit); | |
| __ evpxorq(xmm21, xmm21, xmm21, Assembler::AVX_512bit); | |
| __ evpxorq(xmm22, xmm22, xmm22, Assembler::AVX_512bit); | |
| __ evpxorq(xmm23, xmm23, xmm23, Assembler::AVX_512bit); | |
| __ evpxorq(xmm24, xmm24, xmm24, Assembler::AVX_512bit); | |
| __ evpxorq(xmm25, xmm25, xmm25, Assembler::AVX_512bit); | |
| __ evpxorq(xmm26, xmm26, xmm26, Assembler::AVX_512bit); | |
| __ evpxorq(xmm27, xmm27, xmm27, Assembler::AVX_512bit); | |
| __ evpxorq(xmm28, xmm28, xmm28, Assembler::AVX_512bit); | |
| __ evpxorq(xmm29, xmm29, xmm29, Assembler::AVX_512bit); | |
| __ evpxorq(xmm30, xmm30, xmm30, Assembler::AVX_512bit); | |
| __ cmpl(rounds, 44); | |
| __ jcc(Assembler::belowEqual, EXIT); | |
| __ evpxorq(xmm18, xmm18, xmm18, Assembler::AVX_512bit); | |
| __ evpxorq(xmm5, xmm5, xmm5, Assembler::AVX_512bit); | |
| __ cmpl(rounds, 52); | |
| __ jcc(Assembler::belowEqual, EXIT); | |
| __ evpxorq(xmm6, xmm6, xmm6, Assembler::AVX_512bit); | |
| __ evpxorq(xmm7, xmm7, xmm7, Assembler::AVX_512bit); | |
| __ bind(EXIT); | |
| } | |
| void StubGenerator::gfmul_avx512(XMMRegister GH, XMMRegister HK) { | |
| const XMMRegister TMP1 = xmm0; | |
| const XMMRegister TMP2 = xmm1; | |
| const XMMRegister TMP3 = xmm2; | |
| __ evpclmulqdq(TMP1, GH, HK, 0x11, Assembler::AVX_512bit); | |
| __ evpclmulqdq(TMP2, GH, HK, 0x00, Assembler::AVX_512bit); | |
| __ evpclmulqdq(TMP3, GH, HK, 0x01, Assembler::AVX_512bit); | |
| __ evpclmulqdq(GH, GH, HK, 0x10, Assembler::AVX_512bit); | |
| __ evpxorq(GH, GH, TMP3, Assembler::AVX_512bit); | |
| __ vpsrldq(TMP3, GH, 8, Assembler::AVX_512bit); | |
| __ vpslldq(GH, GH, 8, Assembler::AVX_512bit); | |
| __ evpxorq(TMP1, TMP1, TMP3, Assembler::AVX_512bit); | |
| __ evpxorq(GH, GH, TMP2, Assembler::AVX_512bit); | |
| __ evmovdquq(TMP3, ExternalAddress(ghash_polynomial_reduction_addr()), Assembler::AVX_512bit, r15 /*rscratch*/); | |
| __ evpclmulqdq(TMP2, TMP3, GH, 0x01, Assembler::AVX_512bit); | |
| __ vpslldq(TMP2, TMP2, 8, Assembler::AVX_512bit); | |
| __ evpxorq(GH, GH, TMP2, Assembler::AVX_512bit); | |
| __ evpclmulqdq(TMP2, TMP3, GH, 0x00, Assembler::AVX_512bit); | |
| __ vpsrldq(TMP2, TMP2, 4, Assembler::AVX_512bit); | |
| __ evpclmulqdq(GH, TMP3, GH, 0x10, Assembler::AVX_512bit); | |
| __ vpslldq(GH, GH, 4, Assembler::AVX_512bit); | |
| __ vpternlogq(GH, 0x96, TMP1, TMP2, Assembler::AVX_512bit); | |
| } | |
| // Holds 64 Htbl entries, 32 HKey and 32 HkKey (derived from HKey) | |
| void StubGenerator::generateHtbl_32_blocks_avx512(Register htbl, Register avx512_htbl) { | |
| const XMMRegister HK = xmm6; | |
| const XMMRegister ZT1 = xmm0, ZT2 = xmm1, ZT3 = xmm2, ZT4 = xmm3; | |
| const XMMRegister ZT5 = xmm4, ZT6 = xmm5, ZT7 = xmm7, ZT8 = xmm8; | |
| const XMMRegister ZT10 = xmm10, ZT11 = xmm11, ZT12 = xmm12; | |
| __ movdqu(HK, Address(htbl, 0)); | |
| __ movdqu(ZT10, ExternalAddress(ghash_long_swap_mask_addr()), r15); | |
| __ vpshufb(HK, HK, ZT10, Assembler::AVX_128bit); | |
| __ movdqu(ZT11, ExternalAddress(ghash_polynomial_addr()), r15); | |
| __ movdqu(ZT12, ExternalAddress(ghash_polynomial_two_one_addr()), r15); | |
| // Compute H ^ 2 from the input subkeyH | |
| __ movdqu(ZT3, HK); | |
| __ vpsllq(HK, HK, 1, Assembler::AVX_128bit); | |
| __ vpsrlq(ZT3, ZT3, 63, Assembler::AVX_128bit); | |
| __ movdqu(ZT2, ZT3); | |
| __ vpslldq(ZT3, ZT3, 8, Assembler::AVX_128bit); | |
| __ vpsrldq(ZT2, ZT2, 8, Assembler::AVX_128bit); | |
| __ vpor(HK, HK, ZT3, Assembler::AVX_128bit); | |
| __ vpshufd(ZT3, ZT2, 0x24, Assembler::AVX_128bit); | |
| __ vpcmpeqd(ZT3, ZT3, ZT12, Assembler::AVX_128bit); | |
| __ vpand(ZT3, ZT3, ZT11, Assembler::AVX_128bit); | |
| __ vpxor(HK, HK, ZT3, Assembler::AVX_128bit); | |
| __ movdqu(Address(avx512_htbl, 16 * 31), HK); // H ^ 2 | |
| __ movdqu(ZT5, HK); | |
| __ evinserti64x2(ZT7, ZT7, HK, 3, Assembler::AVX_512bit); | |
| //calculate HashKey ^ 2 << 1 mod poly | |
| gfmul_avx512(ZT5, HK); | |
| __ movdqu(Address(avx512_htbl, 16 * 30), ZT5); | |
| __ evinserti64x2(ZT7, ZT7, ZT5, 2, Assembler::AVX_512bit); | |
| //calculate HashKey ^ 3 << 1 mod poly | |
| gfmul_avx512(ZT5, HK); | |
| __ movdqu(Address(avx512_htbl, 16 * 29), ZT5); | |
| __ evinserti64x2(ZT7, ZT7, ZT5, 1, Assembler::AVX_512bit); | |
| //calculate HashKey ^ 4 << 1 mod poly | |
| gfmul_avx512(ZT5, HK); | |
| __ movdqu(Address(avx512_htbl, 16 * 28), ZT5); | |
| __ evinserti64x2(ZT7, ZT7, ZT5, 0, Assembler::AVX_512bit); | |
| // ZT5 amd ZT7 to be cleared(hash key) | |
| //calculate HashKeyK = HashKey x POLY | |
| __ evmovdquq(xmm11, ExternalAddress(ghash_polynomial_addr()), Assembler::AVX_512bit, r15); | |
| __ evpclmulqdq(ZT1, ZT7, xmm11, 0x10, Assembler::AVX_512bit); | |
| __ vpshufd(ZT2, ZT7, 78, Assembler::AVX_512bit); | |
| __ evpxorq(ZT1, ZT1, ZT2, Assembler::AVX_512bit); | |
| __ evmovdquq(Address(avx512_htbl, 16 * 60), ZT1, Assembler::AVX_512bit); | |
| //**ZT1 amd ZT2 to be cleared(hash key) | |
| //switch to 4x128 - bit computations now | |
| __ evshufi64x2(ZT5, ZT5, ZT5, 0x00, Assembler::AVX_512bit); //;; broadcast HashKey ^ 4 across all ZT5 | |
| __ evmovdquq(ZT8, ZT7, Assembler::AVX_512bit);//; save HashKey ^ 4 to HashKey ^ 1 in ZT8 | |
| //**ZT8 to be cleared(hash key) | |
| //calculate HashKey ^ 5 << 1 mod poly, HashKey ^ 6 << 1 mod poly, ... HashKey ^ 8 << 1 mod poly | |
| gfmul_avx512(ZT7, ZT5); | |
| __ evmovdquq(Address(avx512_htbl, 16 * 24), ZT7, Assembler::AVX_512bit);//; HashKey ^ 8 to HashKey ^ 5 in ZT7 now | |
| //calculate HashKeyX = HashKey x POLY | |
| __ evpclmulqdq(ZT1, ZT7, xmm11, 0x10, Assembler::AVX_512bit); | |
| __ vpshufd(ZT2, ZT7, 78, Assembler::AVX_512bit); | |
| __ evpxorq(ZT1, ZT1, ZT2, Assembler::AVX_512bit); | |
| __ evmovdquq(Address(avx512_htbl, 16 * 56), ZT1, Assembler::AVX_512bit); | |
| __ evshufi64x2(ZT5, ZT7, ZT7, 0x00, Assembler::AVX_512bit);//;; broadcast HashKey ^ 8 across all ZT5 | |
| for (int i = 20, j = 52; i > 0;) { | |
| gfmul_avx512(ZT8, ZT5); | |
| __ evmovdquq(Address(avx512_htbl, 16 * i), ZT8, Assembler::AVX_512bit); | |
| //calculate HashKeyK = HashKey x POLY | |
| __ evpclmulqdq(ZT1, ZT8, xmm11, 0x10, Assembler::AVX_512bit); | |
| __ vpshufd(ZT2, ZT8, 78, Assembler::AVX_512bit); | |
| __ evpxorq(ZT1, ZT1, ZT2, Assembler::AVX_512bit); | |
| __ evmovdquq(Address(avx512_htbl, 16 * j), ZT1, Assembler::AVX_512bit); | |
| i -= 4; | |
| j -= 4; | |
| //compute HashKey ^ (8 + n), HashKey ^ (7 + n), ... HashKey ^ (5 + n) | |
| gfmul_avx512(ZT7, ZT5); | |
| __ evmovdquq(Address(avx512_htbl, 16 * i), ZT7, Assembler::AVX_512bit); | |
| //calculate HashKeyK = HashKey x POLY | |
| __ evpclmulqdq(ZT1, ZT7, xmm11, 0x10, Assembler::AVX_512bit); | |
| __ vpshufd(ZT2, ZT7, 78, Assembler::AVX_512bit); | |
| __ evpxorq(ZT1, ZT1, ZT2, Assembler::AVX_512bit); | |
| __ evmovdquq(Address(avx512_htbl, 16 * j), ZT1, Assembler::AVX_512bit); | |
| i -= 4; | |
| j -= 4; | |
| } | |
| } | |
| #define vhpxori4x128(reg, tmp) \ | |
| __ vextracti64x4(tmp, reg, 1); \ | |
| __ evpxorq(reg, reg, tmp, Assembler::AVX_256bit); \ | |
| __ vextracti32x4(tmp, reg, 1); \ | |
| __ evpxorq(reg, reg, tmp, Assembler::AVX_128bit); \ | |
| #define roundEncode(key, dst1, dst2, dst3, dst4) \ | |
| __ vaesenc(dst1, dst1, key, Assembler::AVX_512bit); \ | |
| __ vaesenc(dst2, dst2, key, Assembler::AVX_512bit); \ | |
| __ vaesenc(dst3, dst3, key, Assembler::AVX_512bit); \ | |
| __ vaesenc(dst4, dst4, key, Assembler::AVX_512bit); \ | |
| #define lastroundEncode(key, dst1, dst2, dst3, dst4) \ | |
| __ vaesenclast(dst1, dst1, key, Assembler::AVX_512bit); \ | |
| __ vaesenclast(dst2, dst2, key, Assembler::AVX_512bit); \ | |
| __ vaesenclast(dst3, dst3, key, Assembler::AVX_512bit); \ | |
| __ vaesenclast(dst4, dst4, key, Assembler::AVX_512bit); \ | |
| #define storeData(dst, position, src1, src2, src3, src4) \ | |
| __ evmovdquq(Address(dst, position, Address::times_1, 0 * 64), src1, Assembler::AVX_512bit); \ | |
| __ evmovdquq(Address(dst, position, Address::times_1, 1 * 64), src2, Assembler::AVX_512bit); \ | |
| __ evmovdquq(Address(dst, position, Address::times_1, 2 * 64), src3, Assembler::AVX_512bit); \ | |
| __ evmovdquq(Address(dst, position, Address::times_1, 3 * 64), src4, Assembler::AVX_512bit); \ | |
| #define loadData(src, position, dst1, dst2, dst3, dst4) \ | |
| __ evmovdquq(dst1, Address(src, position, Address::times_1, 0 * 64), Assembler::AVX_512bit); \ | |
| __ evmovdquq(dst2, Address(src, position, Address::times_1, 1 * 64), Assembler::AVX_512bit); \ | |
| __ evmovdquq(dst3, Address(src, position, Address::times_1, 2 * 64), Assembler::AVX_512bit); \ | |
| __ evmovdquq(dst4, Address(src, position, Address::times_1, 3 * 64), Assembler::AVX_512bit); \ | |
| #define carrylessMultiply(dst00, dst01, dst10, dst11, ghdata, hkey2, hkey1) \ | |
| __ evpclmulqdq(dst00, ghdata, hkey2, 0x00, Assembler::AVX_512bit); \ | |
| __ evpclmulqdq(dst01, ghdata, hkey2, 0x10, Assembler::AVX_512bit); \ | |
| __ evpclmulqdq(dst10, ghdata, hkey1, 0x01, Assembler::AVX_512bit); \ | |
| __ evpclmulqdq(dst11, ghdata, hkey1, 0x11, Assembler::AVX_512bit); \ | |
| #define shuffle(dst0, dst1, dst2, dst3, src0, src1, src2, src3, shufmask) \ | |
| __ vpshufb(dst0, src0, shufmask, Assembler::AVX_512bit); \ | |
| __ vpshufb(dst1, src1, shufmask, Assembler::AVX_512bit); \ | |
| __ vpshufb(dst2, src2, shufmask, Assembler::AVX_512bit); \ | |
| __ vpshufb(dst3, src3, shufmask, Assembler::AVX_512bit); \ | |
| #define xorBeforeStore(dst0, dst1, dst2, dst3, src0, src1, src2, src3) \ | |
| __ evpxorq(dst0, dst0, src0, Assembler::AVX_512bit); \ | |
| __ evpxorq(dst1, dst1, src1, Assembler::AVX_512bit); \ | |
| __ evpxorq(dst2, dst2, src2, Assembler::AVX_512bit); \ | |
| __ evpxorq(dst3, dst3, src3, Assembler::AVX_512bit); \ | |
| #define xorGHASH(dst0, dst1, dst2, dst3, src02, src03, src12, src13, src22, src23, src32, src33) \ | |
| __ vpternlogq(dst0, 0x96, src02, src03, Assembler::AVX_512bit); \ | |
| __ vpternlogq(dst1, 0x96, src12, src13, Assembler::AVX_512bit); \ | |
| __ vpternlogq(dst2, 0x96, src22, src23, Assembler::AVX_512bit); \ | |
| __ vpternlogq(dst3, 0x96, src32, src33, Assembler::AVX_512bit); \ | |
| //schoolbook multiply of 16 blocks(8 x 16 bytes) | |
| //it is assumed that data read is already shuffledand | |
| void StubGenerator::ghash16_avx512(bool start_ghash, bool do_reduction, bool uload_shuffle, bool hk_broadcast, bool do_hxor, | |
| Register in, Register pos, Register subkeyHtbl, XMMRegister HASH, XMMRegister SHUFM, int in_offset, | |
| int in_disp, int displacement, int hashkey_offset) { | |
| const XMMRegister ZTMP0 = xmm0; | |
| const XMMRegister ZTMP1 = xmm3; | |
| const XMMRegister ZTMP2 = xmm4; | |
| const XMMRegister ZTMP3 = xmm5; | |
| const XMMRegister ZTMP4 = xmm6; | |
| const XMMRegister ZTMP5 = xmm7; | |
| const XMMRegister ZTMP6 = xmm10; | |
| const XMMRegister ZTMP7 = xmm11; | |
| const XMMRegister ZTMP8 = xmm12; | |
| const XMMRegister ZTMP9 = xmm13; | |
| const XMMRegister ZTMPA = xmm26; | |
| const XMMRegister ZTMPB = xmm23; | |
| const XMMRegister GH = xmm24; | |
| const XMMRegister GL = xmm25; | |
| const int hkey_gap = 16 * 32; | |
| if (uload_shuffle) { | |
| __ evmovdquq(ZTMP9, Address(subkeyHtbl, in_offset * 16 + in_disp), Assembler::AVX_512bit); | |
| __ vpshufb(ZTMP9, ZTMP9, SHUFM, Assembler::AVX_512bit); | |
| } else { | |
| __ evmovdquq(ZTMP9, Address(subkeyHtbl, in_offset * 16 + in_disp), Assembler::AVX_512bit); | |
| } | |
| if (start_ghash) { | |
| __ evpxorq(ZTMP9, ZTMP9, HASH, Assembler::AVX_512bit); | |
| } | |
| if (hk_broadcast) { | |
| __ evbroadcastf64x2(ZTMP8, Address(subkeyHtbl, hashkey_offset + displacement + 0 * 64), Assembler::AVX_512bit); | |
| __ evbroadcastf64x2(ZTMPA, Address(subkeyHtbl, hashkey_offset + displacement + hkey_gap + 0 * 64), Assembler::AVX_512bit); | |
| } else { | |
| __ evmovdquq(ZTMP8, Address(subkeyHtbl, hashkey_offset + displacement + 0 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(ZTMPA, Address(subkeyHtbl, hashkey_offset + displacement + hkey_gap + 0 * 64), Assembler::AVX_512bit); | |
| } | |
| carrylessMultiply(ZTMP0, ZTMP1, ZTMP2, ZTMP3, ZTMP9, ZTMPA, ZTMP8); | |
| //ghash blocks 4 - 7 | |
| if (uload_shuffle) { | |
| __ evmovdquq(ZTMP9, Address(subkeyHtbl, in_offset * 16 + in_disp + 64), Assembler::AVX_512bit); | |
| __ vpshufb(ZTMP9, ZTMP9, SHUFM, Assembler::AVX_512bit); | |
| } else { | |
| __ evmovdquq(ZTMP9, Address(subkeyHtbl, in_offset * 16 + in_disp + 64), Assembler::AVX_512bit); | |
| } | |
| if (hk_broadcast) { | |
| __ evbroadcastf64x2(ZTMP8, Address(subkeyHtbl, hashkey_offset + displacement + 1 * 64), Assembler::AVX_512bit);; | |
| __ evbroadcastf64x2(ZTMPA, Address(subkeyHtbl, hashkey_offset + displacement + hkey_gap + 1 * 64), Assembler::AVX_512bit); | |
| } else { | |
| __ evmovdquq(ZTMP8, Address(subkeyHtbl, hashkey_offset + displacement + 1 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(ZTMPA, Address(subkeyHtbl, hashkey_offset + displacement + hkey_gap + 1 * 64), Assembler::AVX_512bit); | |
| } | |
| carrylessMultiply(ZTMP4, ZTMP5, ZTMP6, ZTMP7, ZTMP9, ZTMPA, ZTMP8); | |
| //update sums | |
| if (start_ghash) { | |
| __ evpxorq(GL, ZTMP0, ZTMP2, Assembler::AVX_512bit);//T2 = THL + TLL | |
| __ evpxorq(GH, ZTMP1, ZTMP3, Assembler::AVX_512bit);//T1 = THH + TLH | |
| } else { //mid, end, end_reduce | |
| __ vpternlogq(GL, 0x96, ZTMP0, ZTMP2, Assembler::AVX_512bit);//T2 = THL + TLL | |
| __ vpternlogq(GH, 0x96, ZTMP1, ZTMP3, Assembler::AVX_512bit);//T1 = THH + TLH | |
| } | |
| //ghash blocks 8 - 11 | |
| if (uload_shuffle) { | |
| __ evmovdquq(ZTMP9, Address(subkeyHtbl, in_offset * 16 + in_disp + 128), Assembler::AVX_512bit); | |
| __ vpshufb(ZTMP9, ZTMP9, SHUFM, Assembler::AVX_512bit); | |
| } else { | |
| __ evmovdquq(ZTMP9, Address(subkeyHtbl, in_offset * 16 + in_disp + 128), Assembler::AVX_512bit); | |
| } | |
| if (hk_broadcast) { | |
| __ evbroadcastf64x2(ZTMP8, Address(subkeyHtbl, hashkey_offset + displacement + 2 * 64), Assembler::AVX_512bit); | |
| __ evbroadcastf64x2(ZTMPA, Address(subkeyHtbl, hashkey_offset + displacement + hkey_gap + 2 * 64), Assembler::AVX_512bit); | |
| } else { | |
| __ evmovdquq(ZTMP8, Address(subkeyHtbl, hashkey_offset + displacement + 2 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(ZTMPA, Address(subkeyHtbl, hashkey_offset + displacement + hkey_gap + 2 * 64), Assembler::AVX_512bit); | |
| } | |
| carrylessMultiply(ZTMP0, ZTMP1, ZTMP2, ZTMP3, ZTMP9, ZTMPA, ZTMP8); | |
| //update sums | |
| __ vpternlogq(GL, 0x96, ZTMP6, ZTMP4, Assembler::AVX_512bit);//T2 = THL + TLL | |
| __ vpternlogq(GH, 0x96, ZTMP7, ZTMP5, Assembler::AVX_512bit);//T1 = THH + TLH | |
| //ghash blocks 12 - 15 | |
| if (uload_shuffle) { | |
| __ evmovdquq(ZTMP9, Address(subkeyHtbl, in_offset * 16 + in_disp + 192), Assembler::AVX_512bit); | |
| __ vpshufb(ZTMP9, ZTMP9, SHUFM, Assembler::AVX_512bit); | |
| } else { | |
| __ evmovdquq(ZTMP9, Address(subkeyHtbl, in_offset * 16 + in_disp + 192), Assembler::AVX_512bit); | |
| } | |
| if (hk_broadcast) { | |
| __ evbroadcastf64x2(ZTMP8, Address(subkeyHtbl, hashkey_offset + displacement + 3 * 64), Assembler::AVX_512bit); | |
| __ evbroadcastf64x2(ZTMPA, Address(subkeyHtbl, hashkey_offset + displacement + hkey_gap + 3 * 64), Assembler::AVX_512bit); | |
| } else { | |
| __ evmovdquq(ZTMP8, Address(subkeyHtbl, hashkey_offset + displacement + 3 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(ZTMPA, Address(subkeyHtbl, hashkey_offset + displacement + hkey_gap + 3 * 64), Assembler::AVX_512bit); | |
| } | |
| carrylessMultiply(ZTMP4, ZTMP5, ZTMP6, ZTMP7, ZTMP9, ZTMPA, ZTMP8); | |
| //update sums | |
| xorGHASH(GL, GH, GL, GH, ZTMP0, ZTMP2, ZTMP1, ZTMP3, ZTMP6, ZTMP4, ZTMP7, ZTMP5); | |
| if (do_reduction) { | |
| //new reduction | |
| __ evmovdquq(ZTMPB, ExternalAddress(ghash_polynomial_addr()), Assembler::AVX_512bit, rbx /*rscratch*/); | |
| __ evpclmulqdq(HASH, GL, ZTMPB, 0x10, Assembler::AVX_512bit); | |
| __ vpshufd(ZTMP0, GL, 78, Assembler::AVX_512bit); | |
| __ vpternlogq(HASH, 0x96, GH, ZTMP0, Assembler::AVX_512bit); | |
| if (do_hxor) { | |
| vhpxori4x128(HASH, ZTMP0); | |
| } | |
| } | |
| } | |
| //Stitched GHASH of 16 blocks(with reduction) with encryption of 0 blocks | |
| void StubGenerator::gcm_enc_dec_last_avx512(Register len, Register in, Register pos, XMMRegister HASH, XMMRegister SHUFM, Register subkeyHtbl, | |
| int ghashin_offset, int hashkey_offset, bool start_ghash, bool do_reduction) { | |
| //there is 0 blocks to cipher so there are only 16 blocks for ghash and reduction | |
| ghash16_avx512(start_ghash, do_reduction, false, false, true, in, pos, subkeyHtbl, HASH, SHUFM, ghashin_offset, 0, 0, hashkey_offset); | |
| } | |
| //Main GCM macro stitching cipher with GHASH | |
| //encrypts 16 blocks at a time | |
| //ghash the 16 previously encrypted ciphertext blocks | |
| void StubGenerator::ghash16_encrypt_parallel16_avx512(Register in, Register out, Register ct, Register pos, Register avx512_subkeyHtbl, | |
| Register CTR_CHECK, Register NROUNDS, Register key, XMMRegister CTR_BE, XMMRegister GHASH_IN, | |
| XMMRegister ADDBE_4x4, XMMRegister ADDBE_1234, XMMRegister ADD_1234, XMMRegister SHFMSK, | |
| bool hk_broadcast, bool is_hash_start, bool do_hash_reduction, bool do_hash_hxor, | |
| bool no_ghash_in, int ghashin_offset, int aesout_offset, int hashkey_offset) { | |
| const XMMRegister B00_03 = xmm0; | |
| const XMMRegister B04_07 = xmm3; | |
| const XMMRegister B08_11 = xmm4; | |
| const XMMRegister B12_15 = xmm5; | |
| const XMMRegister THH1 = xmm6; | |
| const XMMRegister THL1 = xmm7; | |
| const XMMRegister TLH1 = xmm10; | |
| const XMMRegister TLL1 = xmm11, THH2 = xmm12, THL2 = xmm13, TLH2 = xmm15; | |
| const XMMRegister TLL2 = xmm16, THH3 = xmm17, THL3 = xmm19, TLH3 = xmm20; | |
| const XMMRegister TLL3 = xmm21, DATA1 = xmm17, DATA2 = xmm19, DATA3 = xmm20, DATA4 = xmm21; | |
| const XMMRegister AESKEY1 = xmm30, AESKEY2 = xmm31; | |
| const XMMRegister GHKEY1 = xmm1, GHKEY2 = xmm18, GHDAT1 = xmm8, GHDAT2 = xmm22; | |
| const XMMRegister ZT = xmm23, TO_REDUCE_L = xmm25, TO_REDUCE_H = xmm24; | |
| const int hkey_gap = 16 * 32; | |
| Label blocks_overflow, blocks_ok, skip_shuffle, cont, aes_256, aes_192, last_aes_rnd; | |
| __ cmpb(CTR_CHECK, (256 - 16)); | |
| __ jcc(Assembler::aboveEqual, blocks_overflow); | |
| __ vpaddd(B00_03, CTR_BE, ADDBE_1234, Assembler::AVX_512bit); | |
| __ vpaddd(B04_07, B00_03, ADDBE_4x4, Assembler::AVX_512bit); | |
| __ vpaddd(B08_11, B04_07, ADDBE_4x4, Assembler::AVX_512bit); | |
| __ vpaddd(B12_15, B08_11, ADDBE_4x4, Assembler::AVX_512bit); | |
| __ jmp(blocks_ok); | |
| __ bind(blocks_overflow); | |
| __ vpshufb(CTR_BE, CTR_BE, SHFMSK, Assembler::AVX_512bit); | |
| __ evmovdquq(B12_15, ExternalAddress(counter_mask_linc4_addr()), Assembler::AVX_512bit, rbx /*rscratch*/); | |
| __ vpaddd(B00_03, CTR_BE, ADD_1234, Assembler::AVX_512bit); | |
| __ vpaddd(B04_07, B00_03, B12_15, Assembler::AVX_512bit); | |
| __ vpaddd(B08_11, B04_07, B12_15, Assembler::AVX_512bit); | |
| __ vpaddd(B12_15, B08_11, B12_15, Assembler::AVX_512bit); | |
| shuffle(B00_03, B04_07, B08_11, B12_15, B00_03, B04_07, B08_11, B12_15, SHFMSK); | |
| __ bind(blocks_ok); | |
| //pre - load constants | |
| ev_load_key(AESKEY1, key, 0, rbx); | |
| if (!no_ghash_in) { | |
| __ evpxorq(GHDAT1, GHASH_IN, Address(avx512_subkeyHtbl, 16 * ghashin_offset), Assembler::AVX_512bit); | |
| } else { | |
| __ evmovdquq(GHDAT1, Address(avx512_subkeyHtbl, 16 * ghashin_offset), Assembler::AVX_512bit); | |
| } | |
| if (hk_broadcast) { | |
| __ evbroadcastf64x2(GHKEY1, Address(avx512_subkeyHtbl, hashkey_offset + 0 * 64), Assembler::AVX_512bit); | |
| __ evbroadcastf64x2(GHKEY2, Address(avx512_subkeyHtbl, hashkey_offset + hkey_gap + 0 * 64), Assembler::AVX_512bit); | |
| } else { | |
| __ evmovdquq(GHKEY1, Address(avx512_subkeyHtbl, hashkey_offset + 0 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(GHKEY2, Address(avx512_subkeyHtbl, hashkey_offset + hkey_gap + 0 * 64), Assembler::AVX_512bit); | |
| } | |
| //save counter for the next round | |
| //increment counter overflow check register | |
| __ evshufi64x2(CTR_BE, B12_15, B12_15, 255, Assembler::AVX_512bit); | |
| __ addb(CTR_CHECK, 16); | |
| //pre - load constants | |
| ev_load_key(AESKEY2, key, 1 * 16, rbx); | |
| __ evmovdquq(GHDAT2, Address(avx512_subkeyHtbl, 16 * (ghashin_offset +4)), Assembler::AVX_512bit); | |
| //stitch AES rounds with GHASH | |
| //AES round 0 | |
| __ evpxorq(B00_03, B00_03, AESKEY1, Assembler::AVX_512bit); | |
| __ evpxorq(B04_07, B04_07, AESKEY1, Assembler::AVX_512bit); | |
| __ evpxorq(B08_11, B08_11, AESKEY1, Assembler::AVX_512bit); | |
| __ evpxorq(B12_15, B12_15, AESKEY1, Assembler::AVX_512bit); | |
| ev_load_key(AESKEY1, key, 2 * 16, rbx); | |
| //GHASH 4 blocks(15 to 12) | |
| carrylessMultiply(TLL1, TLH1, THL1, THH1, GHDAT1, GHKEY2, GHKEY1); | |
| if (hk_broadcast) { | |
| __ evbroadcastf64x2(GHKEY1, Address(avx512_subkeyHtbl, hashkey_offset + 1 * 64), Assembler::AVX_512bit); | |
| __ evbroadcastf64x2(GHKEY2, Address(avx512_subkeyHtbl, hashkey_offset + hkey_gap + 1 * 64), Assembler::AVX_512bit); | |
| } else { | |
| __ evmovdquq(GHKEY1, Address(avx512_subkeyHtbl, hashkey_offset + 1 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(GHKEY2, Address(avx512_subkeyHtbl, hashkey_offset + hkey_gap + 1 * 64), Assembler::AVX_512bit); | |
| } | |
| __ evmovdquq(GHDAT1, Address(avx512_subkeyHtbl, 16 * (ghashin_offset + 8)), Assembler::AVX_512bit); | |
| //AES round 1 | |
| roundEncode(AESKEY2, B00_03, B04_07, B08_11, B12_15); | |
| ev_load_key(AESKEY2, key, 3 * 16, rbx); | |
| //GHASH 4 blocks(11 to 8) | |
| carrylessMultiply(TLL2, TLH2, THL2, THH2, GHDAT2, GHKEY2, GHKEY1); | |
| if (hk_broadcast) { | |
| __ evbroadcastf64x2(GHKEY1, Address(avx512_subkeyHtbl, hashkey_offset + 2 * 64), Assembler::AVX_512bit); | |
| __ evbroadcastf64x2(GHKEY2, Address(avx512_subkeyHtbl, hashkey_offset + hkey_gap + 2 * 64), Assembler::AVX_512bit); | |
| } else { | |
| __ evmovdquq(GHKEY1, Address(avx512_subkeyHtbl, hashkey_offset + 2 * 64 ), Assembler::AVX_512bit); | |
| __ evmovdquq(GHKEY2, Address(avx512_subkeyHtbl, hashkey_offset + hkey_gap + 2 * 64), Assembler::AVX_512bit); | |
| } | |
| __ evmovdquq(GHDAT2, Address(avx512_subkeyHtbl, 16 * (ghashin_offset + 12)), Assembler::AVX_512bit); | |
| //AES round 2 | |
| roundEncode(AESKEY1, B00_03, B04_07, B08_11, B12_15); | |
| ev_load_key(AESKEY1, key, 4 * 16, rbx); | |
| //GHASH 4 blocks(7 to 4) | |
| carrylessMultiply(TLL3, TLH3, THL3, THH3, GHDAT1, GHKEY2, GHKEY1); | |
| if (hk_broadcast) { | |
| __ evbroadcastf64x2(GHKEY1, Address(avx512_subkeyHtbl, hashkey_offset + 3 * 64), Assembler::AVX_512bit); | |
| __ evbroadcastf64x2(GHKEY2, Address(avx512_subkeyHtbl, hashkey_offset + hkey_gap + 3 * 64), Assembler::AVX_512bit); | |
| } else { | |
| __ evmovdquq(GHKEY1, Address(avx512_subkeyHtbl, hashkey_offset + 3 * 64), Assembler::AVX_512bit); | |
| __ evmovdquq(GHKEY2, Address(avx512_subkeyHtbl, hashkey_offset + hkey_gap + 3 * 64), Assembler::AVX_512bit); | |
| } | |
| //AES rounds 3 | |
| roundEncode(AESKEY2, B00_03, B04_07, B08_11, B12_15); | |
| ev_load_key(AESKEY2, key, 5 * 16, rbx); | |
| //Gather(XOR) GHASH for 12 blocks | |
| xorGHASH(TLL1, TLH1, THL1, THH1, TLL2, TLL3, TLH2, TLH3, THL2, THL3, THH2, THH3); | |
| //AES rounds 4 | |
| roundEncode(AESKEY1, B00_03, B04_07, B08_11, B12_15); | |
| ev_load_key(AESKEY1, key, 6 * 16, rbx); | |
| //load plain / cipher text(recycle GH3xx registers) | |
| loadData(in, pos, DATA1, DATA2, DATA3, DATA4); | |
| //AES rounds 5 | |
| roundEncode(AESKEY2, B00_03, B04_07, B08_11, B12_15); | |
| ev_load_key(AESKEY2, key, 7 * 16, rbx); | |
| //GHASH 4 blocks(3 to 0) | |
| carrylessMultiply(TLL2, TLH2, THL2, THH2, GHDAT2, GHKEY2, GHKEY1); | |
| //AES round 6 | |
| roundEncode(AESKEY1, B00_03, B04_07, B08_11, B12_15); | |
| ev_load_key(AESKEY1, key, 8 * 16, rbx); | |
| //gather GHASH in TO_REDUCE_H / L | |
| if (is_hash_start) { | |
| __ evpxorq(TO_REDUCE_L, TLL2, THL2, Assembler::AVX_512bit); | |
| __ evpxorq(TO_REDUCE_H, THH2, TLH2, Assembler::AVX_512bit); | |
| __ vpternlogq(TO_REDUCE_L, 0x96, TLL1, THL1, Assembler::AVX_512bit); | |
| __ vpternlogq(TO_REDUCE_H, 0x96, THH1, TLH1, Assembler::AVX_512bit); | |
| } else { | |
| //not the first round so sums need to be updated | |
| xorGHASH(TO_REDUCE_L, TO_REDUCE_H, TO_REDUCE_L, TO_REDUCE_H, TLL2, THL2, THH2, TLH2, TLL1, THL1, THH1, TLH1); | |
| } | |
| //AES round 7 | |
| roundEncode(AESKEY2, B00_03, B04_07, B08_11, B12_15); | |
| ev_load_key(AESKEY2, key, 9 * 16, rbx); | |
| //new reduction | |
| if (do_hash_reduction) { | |
| __ evmovdquq(ZT, ExternalAddress(ghash_polynomial_reduction_addr()), Assembler::AVX_512bit, rbx /*rscratch*/); | |
| __ evpclmulqdq(THH1, TO_REDUCE_L, ZT, 0x10, Assembler::AVX_512bit); | |
| __ vpshufd(TO_REDUCE_L, TO_REDUCE_L, 78, Assembler::AVX_512bit); | |
| __ vpternlogq(THH1, 0x96, TO_REDUCE_H, TO_REDUCE_L, Assembler::AVX_512bit); | |
| } | |
| //AES round 8 | |
| roundEncode(AESKEY1, B00_03, B04_07, B08_11, B12_15); | |
| ev_load_key(AESKEY1, key, 10 * 16, rbx); | |
| //horizontalxor of 4 reduced hashes | |
| if (do_hash_hxor) { | |
| vhpxori4x128(THH1, TLL1); | |
| } | |
| //AES round 9 | |
| roundEncode(AESKEY2, B00_03, B04_07, B08_11, B12_15); | |
| //AES rounds up to 11 (AES192) or 13 (AES256) | |
| //AES128 is done | |
| __ cmpl(NROUNDS, 52); | |
| __ jcc(Assembler::less, last_aes_rnd); | |
| __ bind(aes_192); | |
| ev_load_key(AESKEY2, key, 11 * 16, rbx); | |
| roundEncode(AESKEY1, B00_03, B04_07, B08_11, B12_15); | |
| ev_load_key(AESKEY1, key, 12 * 16, rbx); | |
| roundEncode(AESKEY2, B00_03, B04_07, B08_11, B12_15); | |
| __ cmpl(NROUNDS, 60); | |
| __ jcc(Assembler::less, last_aes_rnd); | |
| __ bind(aes_256); | |
| ev_load_key(AESKEY2, key, 13 * 16, rbx); | |
| roundEncode(AESKEY1, B00_03, B04_07, B08_11, B12_15); | |
| ev_load_key(AESKEY1, key, 14 * 16, rbx); | |
| roundEncode(AESKEY2, B00_03, B04_07, B08_11, B12_15); | |
| __ bind(last_aes_rnd); | |
| //the last AES round | |
| lastroundEncode(AESKEY1, B00_03, B04_07, B08_11, B12_15); | |
| //AESKEY1and AESKEY2 contain AES round keys | |
| //XOR against plain / cipher text | |
| xorBeforeStore(B00_03, B04_07, B08_11, B12_15, DATA1, DATA2, DATA3, DATA4); | |
| //store cipher / plain text | |
| storeData(out, pos, B00_03, B04_07, B08_11, B12_15); | |
| //**B00_03, B04_07, B08_011, B12_B15 may contain sensitive data | |
| //shuffle cipher text blocks for GHASH computation | |
| __ cmpptr(ct, out); | |
| __ jcc(Assembler::notEqual, skip_shuffle); | |
| shuffle(B00_03, B04_07, B08_11, B12_15, B00_03, B04_07, B08_11, B12_15, SHFMSK); | |
| __ jmp(cont); | |
| __ bind(skip_shuffle); | |
| shuffle(B00_03, B04_07, B08_11, B12_15, DATA1, DATA2, DATA3, DATA4, SHFMSK); | |
| //**B00_03, B04_07, B08_011, B12_B15 overwritten with shuffled cipher text | |
| __ bind(cont); | |
| //store shuffled cipher text for ghashing | |
| __ evmovdquq(Address(avx512_subkeyHtbl, 16 * aesout_offset), B00_03, Assembler::AVX_512bit); | |
| __ evmovdquq(Address(avx512_subkeyHtbl, 16 * (aesout_offset + 4)), B04_07, Assembler::AVX_512bit); | |
| __ evmovdquq(Address(avx512_subkeyHtbl, 16 * (aesout_offset + 8)), B08_11, Assembler::AVX_512bit); | |
| __ evmovdquq(Address(avx512_subkeyHtbl, 16 * (aesout_offset + 12)), B12_15, Assembler::AVX_512bit); | |
| } | |
| //Encrypt / decrypt the initial 16 blocks | |
| void StubGenerator::initial_blocks_16_avx512(Register in, Register out, Register ct, Register pos, Register key, Register avx512_subkeyHtbl, | |
| Register CTR_CHECK, Register rounds, XMMRegister CTR, XMMRegister GHASH, XMMRegister ADDBE_4x4, | |
| XMMRegister ADDBE_1234, XMMRegister ADD_1234, XMMRegister SHUF_MASK, int stack_offset) { | |
| const XMMRegister B00_03 = xmm7; | |
| const XMMRegister B04_07 = xmm10; | |
| const XMMRegister B08_11 = xmm11; | |
| const XMMRegister B12_15 = xmm12; | |
| const XMMRegister T0 = xmm0; | |
| const XMMRegister T1 = xmm3; | |
| const XMMRegister T2 = xmm4; | |
| const XMMRegister T3 = xmm5; | |
| const XMMRegister T4 = xmm6; | |
| const XMMRegister T5 = xmm30; | |
| Label next_16_overflow, next_16_ok, cont, skip_shuffle, aes_256, aes_192, last_aes_rnd; | |
| //prepare counter blocks | |
| __ cmpb(CTR_CHECK, (256 - 16)); | |
| __ jcc(Assembler::aboveEqual, next_16_overflow); | |
| __ vpaddd(B00_03, CTR, ADDBE_1234, Assembler::AVX_512bit); | |
| __ vpaddd(B04_07, B00_03, ADDBE_4x4, Assembler::AVX_512bit); | |
| __ vpaddd(B08_11, B04_07, ADDBE_4x4, Assembler::AVX_512bit); | |
| __ vpaddd(B12_15, B08_11, ADDBE_4x4, Assembler::AVX_512bit); | |
| __ jmp(next_16_ok); | |
| __ bind(next_16_overflow); | |
| __ vpshufb(CTR, CTR, SHUF_MASK, Assembler::AVX_512bit); | |
| __ evmovdquq(B12_15, ExternalAddress(counter_mask_linc4_addr()), Assembler::AVX_512bit, rbx); | |
| __ vpaddd(B00_03, CTR, ADD_1234, Assembler::AVX_512bit); | |
| __ vpaddd(B04_07, B00_03, B12_15, Assembler::AVX_512bit); | |
| __ vpaddd(B08_11, B04_07, B12_15, Assembler::AVX_512bit); | |
| __ vpaddd(B12_15, B08_11, B12_15, Assembler::AVX_512bit); | |
| shuffle(B00_03, B04_07, B08_11, B12_15, B00_03, B04_07, B08_11, B12_15, SHUF_MASK); | |
| __ bind(next_16_ok); | |
| __ evshufi64x2(CTR, B12_15, B12_15, 255, Assembler::AVX_512bit); | |
| __ addb(CTR_CHECK, 16); | |
| //load 16 blocks of data | |
| loadData(in, pos, T0, T1, T2, T3); | |
| //move to AES encryption rounds | |
| __ movdqu(T5, ExternalAddress(key_shuffle_mask_addr()), rbx /*rscratch*/); | |
| ev_load_key(T4, key, 0, T5); | |
| __ evpxorq(B00_03, B00_03, T4, Assembler::AVX_512bit); | |
| __ evpxorq(B04_07, B04_07, T4, Assembler::AVX_512bit); | |
| __ evpxorq(B08_11, B08_11, T4, Assembler::AVX_512bit); | |
| __ evpxorq(B12_15, B12_15, T4, Assembler::AVX_512bit); | |
| for (int i = 1; i < 10; i++) { | |
| ev_load_key(T4, key, i * 16, T5); | |
| roundEncode(T4, B00_03, B04_07, B08_11, B12_15); | |
| } | |
| ev_load_key(T4, key, 10 * 16, T5); | |
| __ cmpl(rounds, 52); | |
| __ jcc(Assembler::less, last_aes_rnd); | |
| __ bind(aes_192); | |
| roundEncode(T4, B00_03, B04_07, B08_11, B12_15); | |
| ev_load_key(T4, key, 16 * 11, T5); | |
| roundEncode(T4, B00_03, B04_07, B08_11, B12_15); | |
| ev_load_key(T4, key, 16 * 12, T5); | |
| __ cmpl(rounds, 60); | |
| __ jcc(Assembler::less, last_aes_rnd); | |
| __ bind(aes_256); | |
| roundEncode(T4, B00_03, B04_07, B08_11, B12_15); | |
| ev_load_key(T4, key, 16 * 13, T5); | |
| roundEncode(T4, B00_03, B04_07, B08_11, B12_15); | |
| ev_load_key(T4, key, 16 * 14, T5); | |
| __ bind(last_aes_rnd); | |
| lastroundEncode(T4, B00_03, B04_07, B08_11, B12_15); | |
| //xor against text | |
| xorBeforeStore(B00_03, B04_07, B08_11, B12_15, T0, T1, T2, T3); | |
| //store | |
| storeData(out, pos, B00_03, B04_07, B08_11, B12_15); | |
| __ cmpptr(ct, out); | |
| __ jcc(Assembler::equal, skip_shuffle); | |
| //decryption - cipher text needs to go to GHASH phase | |
| shuffle(B00_03, B04_07, B08_11, B12_15, T0, T1, T2, T3, SHUF_MASK); | |
| __ jmp(cont); | |
| __ bind(skip_shuffle); | |
| shuffle(B00_03, B04_07, B08_11, B12_15, B00_03, B04_07, B08_11, B12_15, SHUF_MASK); | |
| //B00_03, B04_07, B08_11, B12_15 overwritten with shuffled cipher text | |
| __ bind(cont); | |
| __ evmovdquq(Address(avx512_subkeyHtbl, 16 * stack_offset), B00_03, Assembler::AVX_512bit); | |
| __ evmovdquq(Address(avx512_subkeyHtbl, 16 * (stack_offset + 4)), B04_07, Assembler::AVX_512bit); | |
| __ evmovdquq(Address(avx512_subkeyHtbl, 16 * (stack_offset + 8)), B08_11, Assembler::AVX_512bit); | |
| __ evmovdquq(Address(avx512_subkeyHtbl, 16 * (stack_offset + 12)), B12_15, Assembler::AVX_512bit); | |
| } | |
| void StubGenerator::aesgcm_avx512(Register in, Register len, Register ct, Register out, Register key, Register state, | |
| Register subkeyHtbl, Register avx512_subkeyHtbl, Register counter) { | |
| Label ENC_DEC_DONE, MESG_BELOW_32_BLKS, NO_BIG_BLKS, ENCRYPT_BIG_BLKS_NO_HXOR, | |
| ENCRYPT_BIG_NBLKS, ENCRYPT_16_BLKS, ENCRYPT_N_GHASH_32_N_BLKS, GHASH_DONE; | |
| const XMMRegister CTR_BLOCKx = xmm2; | |
| const XMMRegister AAD_HASHx = xmm14; | |
| const XMMRegister ZTMP0 = xmm0; | |
| const XMMRegister ZTMP1 = xmm3; //**sensitive | |
| const XMMRegister ZTMP2 = xmm4; //**sensitive(small data) | |
| const XMMRegister ZTMP3 = xmm5; //**sensitive(small data) | |
| const XMMRegister ZTMP4 = xmm6; | |
| const XMMRegister ZTMP5 = xmm7; | |
| const XMMRegister ZTMP6 = xmm10; | |
| const XMMRegister ZTMP7 = xmm11; | |
| const XMMRegister ZTMP8 = xmm12; | |
| const XMMRegister ZTMP9 = xmm13; | |
| const XMMRegister ZTMP10 = xmm15; | |
| const XMMRegister ZTMP11 = xmm16; | |
| const XMMRegister ZTMP12 = xmm17; | |
| const XMMRegister ZTMP13 = xmm19; | |
| const XMMRegister ZTMP14 = xmm20; | |
| const XMMRegister ZTMP15 = xmm21; | |
| const XMMRegister ZTMP16 = xmm30; | |
| const XMMRegister ZTMP17 = xmm31; | |
| const XMMRegister ZTMP18 = xmm1; | |
| const XMMRegister ZTMP19 = xmm18; | |
| const XMMRegister ZTMP20 = xmm8; | |
| const XMMRegister ZTMP21 = xmm22; | |
| const XMMRegister ZTMP22 = xmm23; | |
| const XMMRegister ZTMP23 = xmm26; | |
| const XMMRegister GH = xmm24; | |
| const XMMRegister GL = xmm25; | |
| const XMMRegister SHUF_MASK = xmm29; | |
| const XMMRegister ADDBE_4x4 = xmm27; | |
| const XMMRegister ADDBE_1234 = xmm28; | |
| const XMMRegister ADD_1234 = xmm9; | |
| const KRegister MASKREG = k1; | |
| const Register pos = rax; | |
| const Register rounds = r15; | |
| const Register CTR_CHECK = r14; | |
| const int stack_offset = 64; | |
| const int ghashin_offset = 64; | |
| const int aesout_offset = 64; | |
| const int hashkey_offset = 0; | |
| const int hashkey_gap = 16 * 32; | |
| const int HashKey_32 = 0; | |
| const int HashKey_16 = 16 * 16; | |
| __ movl(pos, 0); | |
| __ cmpl(len, 256); | |
| __ jcc(Assembler::lessEqual, ENC_DEC_DONE); | |
| /* Structure of the Htbl is as follows: | |
| * Where 0 - 31 we have 32 Hashkey's and 32-63 we have 32 HashKeyK (derived from HashKey) | |
| * Rest 8 entries are for storing CTR values post AES rounds | |
| * ---------------------------------------------------------------------------------------- | |
| Hashkey32 -> 16 * 0 | |
| Hashkey31 -> 16 * 1 | |
| Hashkey30 -> 16 * 2 | |
| ........ | |
| Hashkey1 -> 16 * 31 | |
| --------------------- | |
| HaskeyK32 -> 16 * 32 | |
| HashkeyK31 -> 16 * 33 | |
| ......... | |
| HashkeyK1 -> 16 * 63 | |
| --------------------- | |
| 1st set of AES Entries | |
| B00_03 -> 16 * 64 | |
| B04_07 -> 16 * 68 | |
| B08_11 -> 16 * 72 | |
| B12_15 -> 16 * 80 | |
| --------------------- | |
| 2nd set of AES Entries | |
| B00_03 -> 16 * 84 | |
| B04_07 -> 16 * 88 | |
| B08_11 -> 16 * 92 | |
| B12_15 -> 16 * 96 | |
| ---------------------*/ | |
| generateHtbl_32_blocks_avx512(subkeyHtbl, avx512_subkeyHtbl); | |
| //Move initial counter value and STATE value into variables | |
| __ movdqu(CTR_BLOCKx, Address(counter, 0)); | |
| __ movdqu(AAD_HASHx, Address(state, 0)); | |
| //Load lswap mask for ghash | |
| __ movdqu(xmm24, ExternalAddress(ghash_long_swap_mask_addr()), rbx /*rscratch*/); | |
| //Shuffle input state using lswap mask | |
| __ vpshufb(AAD_HASHx, AAD_HASHx, xmm24, Assembler::AVX_128bit); | |
| // Compute #rounds for AES based on the length of the key array | |
| __ movl(rounds, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); | |
| __ evmovdquq(ADDBE_4x4, ExternalAddress(counter_mask_addbe_4444_addr()), Assembler::AVX_512bit, rbx /*rscratch*/); | |
| __ evmovdquq(ADDBE_1234, ExternalAddress(counter_mask_addbe_1234_addr()), Assembler::AVX_512bit, rbx /*rscratch*/); | |
| __ evmovdquq(SHUF_MASK, ExternalAddress(counter_shuffle_mask_addr()), Assembler::AVX_512bit, rbx /*rscratch*/); | |
| __ evmovdquq(ADD_1234, ExternalAddress(counter_mask_add_1234_addr()), Assembler::AVX_512bit, rbx /*rscratch*/); | |
| //Shuffle counter, subtract 1 from the pre-incremented counter value and broadcast counter value to 512 bit register | |
| __ vpshufb(CTR_BLOCKx, CTR_BLOCKx, SHUF_MASK, Assembler::AVX_128bit); | |
| __ vpsubd(CTR_BLOCKx, CTR_BLOCKx, ADD_1234, Assembler::AVX_128bit); | |
| __ evshufi64x2(CTR_BLOCKx, CTR_BLOCKx, CTR_BLOCKx, 0, Assembler::AVX_512bit); | |
| __ movdl(CTR_CHECK, CTR_BLOCKx); | |
| __ andl(CTR_CHECK, 255); | |
| // Reshuffle counter | |
| __ vpshufb(CTR_BLOCKx, CTR_BLOCKx, SHUF_MASK, Assembler::AVX_512bit); | |
| initial_blocks_16_avx512(in, out, ct, pos, key, avx512_subkeyHtbl, CTR_CHECK, rounds, CTR_BLOCKx, AAD_HASHx, ADDBE_4x4, ADDBE_1234, ADD_1234, SHUF_MASK, stack_offset); | |
| __ addl(pos, 16 * 16); | |
| __ cmpl(len, 32 * 16); | |
| __ jcc(Assembler::below, MESG_BELOW_32_BLKS); | |
| initial_blocks_16_avx512(in, out, ct, pos, key, avx512_subkeyHtbl, CTR_CHECK, rounds, CTR_BLOCKx, AAD_HASHx, ADDBE_4x4, ADDBE_1234, ADD_1234, SHUF_MASK, stack_offset + 16); | |
| __ addl(pos, 16 * 16); | |
| __ subl(len, 32 * 16); | |
| __ cmpl(len, 32 * 16); | |
| __ jcc(Assembler::below, NO_BIG_BLKS); | |
| __ bind(ENCRYPT_BIG_BLKS_NO_HXOR); | |
| __ cmpl(len, 2 * 32 * 16); | |
| __ jcc(Assembler::below, ENCRYPT_BIG_NBLKS); | |
| ghash16_encrypt_parallel16_avx512(in, out, ct, pos, avx512_subkeyHtbl, CTR_CHECK, rounds, key, CTR_BLOCKx, AAD_HASHx, ADDBE_4x4, ADDBE_1234, ADD_1234, SHUF_MASK, | |
| true, true, false, false, false, ghashin_offset, aesout_offset, HashKey_32); | |
| __ addl(pos, 16 * 16); | |
| ghash16_encrypt_parallel16_avx512(in, out, ct, pos, avx512_subkeyHtbl, CTR_CHECK, rounds, key, CTR_BLOCKx, AAD_HASHx, ADDBE_4x4, ADDBE_1234, ADD_1234, SHUF_MASK, | |
| true, false, true, false, true, ghashin_offset + 16, aesout_offset + 16, HashKey_16); | |
| __ evmovdquq(AAD_HASHx, ZTMP4, Assembler::AVX_512bit); | |
| __ addl(pos, 16 * 16); | |
| __ subl(len, 32 * 16); | |
| __ jmp(ENCRYPT_BIG_BLKS_NO_HXOR); | |
| __ bind(ENCRYPT_BIG_NBLKS); | |
| ghash16_encrypt_parallel16_avx512(in, out, ct, pos, avx512_subkeyHtbl, CTR_CHECK, rounds, key, CTR_BLOCKx, AAD_HASHx, ADDBE_4x4, ADDBE_1234, ADD_1234, SHUF_MASK, | |
| false, true, false, false, false, ghashin_offset, aesout_offset, HashKey_32); | |
| __ addl(pos, 16 * 16); | |
| ghash16_encrypt_parallel16_avx512(in, out, ct, pos, avx512_subkeyHtbl, CTR_CHECK, rounds, key, CTR_BLOCKx, AAD_HASHx, ADDBE_4x4, ADDBE_1234, ADD_1234, SHUF_MASK, | |
| false, false, true, true, true, ghashin_offset + 16, aesout_offset + 16, HashKey_16); | |
| __ movdqu(AAD_HASHx, ZTMP4); | |
| __ addl(pos, 16 * 16); | |
| __ subl(len, 32 * 16); | |
| __ bind(NO_BIG_BLKS); | |
| __ cmpl(len, 16 * 16); | |
| __ jcc(Assembler::aboveEqual, ENCRYPT_16_BLKS); | |
| __ bind(ENCRYPT_N_GHASH_32_N_BLKS); | |
| ghash16_avx512(true, false, false, false, true, in, pos, avx512_subkeyHtbl, AAD_HASHx, SHUF_MASK, stack_offset, 0, 0, HashKey_32); | |
| gcm_enc_dec_last_avx512(len, in, pos, AAD_HASHx, SHUF_MASK, avx512_subkeyHtbl, ghashin_offset + 16, HashKey_16, false, true); | |
| __ jmp(GHASH_DONE); | |
| __ bind(ENCRYPT_16_BLKS); | |
| ghash16_encrypt_parallel16_avx512(in, out, ct, pos, avx512_subkeyHtbl, CTR_CHECK, rounds, key, CTR_BLOCKx, AAD_HASHx, ADDBE_4x4, ADDBE_1234, ADD_1234, SHUF_MASK, | |
| false, true, false, false, false, ghashin_offset, aesout_offset, HashKey_32); | |
| ghash16_avx512(false, true, false, false, true, in, pos, avx512_subkeyHtbl, AAD_HASHx, SHUF_MASK, stack_offset, 16 * 16, 0, HashKey_16); | |
| __ bind(MESG_BELOW_32_BLKS); | |
| __ subl(len, 16 * 16); | |
| __ addl(pos, 16 * 16); | |
| gcm_enc_dec_last_avx512(len, in, pos, AAD_HASHx, SHUF_MASK, avx512_subkeyHtbl, ghashin_offset, HashKey_16, true, true); | |
| __ bind(GHASH_DONE); | |
| //Pre-increment counter for next operation, make sure that counter value is incremented on the LSB | |
| __ vpshufb(CTR_BLOCKx, CTR_BLOCKx, SHUF_MASK, Assembler::AVX_128bit); | |
| __ vpaddd(CTR_BLOCKx, CTR_BLOCKx, ADD_1234, Assembler::AVX_128bit); | |
| __ vpshufb(CTR_BLOCKx, CTR_BLOCKx, SHUF_MASK, Assembler::AVX_128bit); | |
| __ movdqu(Address(counter, 0), CTR_BLOCKx); | |
| //Load ghash lswap mask | |
| __ movdqu(xmm24, ExternalAddress(ghash_long_swap_mask_addr()), rbx /*rscratch*/); | |
| //Shuffle ghash using lbswap_mask and store it | |
| __ vpshufb(AAD_HASHx, AAD_HASHx, xmm24, Assembler::AVX_128bit); | |
| __ movdqu(Address(state, 0), AAD_HASHx); | |
| //Zero out sensitive data | |
| __ evpxorq(ZTMP21, ZTMP21, ZTMP21, Assembler::AVX_512bit); | |
| __ evpxorq(ZTMP0, ZTMP0, ZTMP0, Assembler::AVX_512bit); | |
| __ evpxorq(ZTMP1, ZTMP1, ZTMP1, Assembler::AVX_512bit); | |
| __ evpxorq(ZTMP2, ZTMP2, ZTMP2, Assembler::AVX_512bit); | |
| __ evpxorq(ZTMP3, ZTMP3, ZTMP3, Assembler::AVX_512bit); | |
| __ bind(ENC_DEC_DONE); | |
| } | |
| //Implements data * hashkey mod (128, 127, 126, 121, 0) | |
| //Inputs: | |
| //GH and HK - 128 bits each | |
| //Output: | |
| //GH = GH * Hashkey mod poly | |
| //Temp registers: xmm1, xmm2, xmm3, r15 | |
| void StubGenerator::gfmul_avx2(XMMRegister GH, XMMRegister HK) { | |
| const XMMRegister T1 = xmm1; | |
| const XMMRegister T2 = xmm2; | |
| const XMMRegister T3 = xmm3; | |
| __ vpclmulqdq(T1, GH, HK, 0x11); // %%T1 = a1*b1 | |
| __ vpclmulqdq(T2, GH, HK, 0x00); // %%T2 = a0*b0 | |
| __ vpclmulqdq(T3, GH, HK, 0x01); // %%T3 = a1*b0 | |
| __ vpclmulqdq(GH, GH, HK, 0x10); // %%GH = a0*b1 | |
| __ vpxor(GH, GH, T3, Assembler::AVX_128bit); | |
| __ vpsrldq(T3, GH, 8, Assembler::AVX_128bit); // shift-R %%GH 2 DWs | |
| __ vpslldq(GH, GH, 8, Assembler::AVX_128bit); // shift-L %%GH 2 DWs | |
| __ vpxor(T1, T1, T3, Assembler::AVX_128bit); | |
| __ vpxor(GH, GH, T2, Assembler::AVX_128bit); | |
| //first phase of the reduction | |
| __ movdqu(T3, ExternalAddress(ghash_polynomial_reduction_addr()), r15 /*rscratch*/); | |
| __ vpclmulqdq(T2, T3, GH, 0x01); | |
| __ vpslldq(T2, T2, 8, Assembler::AVX_128bit); // shift-L %%T2 2 DWs | |
| __ vpxor(GH, GH, T2, Assembler::AVX_128bit); // first phase of the reduction complete | |
| //second phase of the reduction | |
| __ vpclmulqdq(T2, T3, GH, 0x00); | |
| __ vpsrldq(T2, T2, 4, Assembler::AVX_128bit); // shift-R %%T2 1 DW (Shift-R only 1-DW to obtain 2-DWs shift-R) | |
| __ vpclmulqdq(GH, T3, GH, 0x10); | |
| __ vpslldq(GH, GH, 4, Assembler::AVX_128bit); // shift-L %%GH 1 DW (Shift-L 1-DW to obtain result with no shifts) | |
| __ vpxor(GH, GH, T2, Assembler::AVX_128bit); // second phase of the reduction complete | |
| __ vpxor(GH, GH, T1, Assembler::AVX_128bit); // the result is in %%GH | |
| } | |
| //Generate 8 constants from the given subkeyH. | |
| //Input: | |
| //htbl - table containing the initial subkeyH | |
| //Output: | |
| //htbl - containing 8 H constants | |
| //Temp registers: xmm0, xmm1, xmm2, xmm3, xmm6, xmm11, xmm12, r15, rbx | |
| void StubGenerator::generateHtbl_8_block_avx2(Register htbl) { | |
| const XMMRegister HK = xmm6; | |
| __ movdqu(HK, Address(htbl, 0)); | |
| __ movdqu(xmm1, ExternalAddress(ghash_long_swap_mask_addr()), rbx /*rscratch*/); | |
| __ vpshufb(HK, HK, xmm1, Assembler::AVX_128bit); | |
| __ movdqu(xmm11, ExternalAddress(ghash_polynomial_addr()), rbx /*rscratch*/); | |
| __ movdqu(xmm12, ExternalAddress(ghash_polynomial_two_one_addr()), rbx /*rscratch*/); | |
| // Compute H ^ 2 from the input subkeyH | |
| __ vpsrlq(xmm1, xmm6, 63, Assembler::AVX_128bit); | |
| __ vpsllq(xmm6, xmm6, 1, Assembler::AVX_128bit); | |
| __ vpslldq(xmm2, xmm1, 8, Assembler::AVX_128bit); | |
| __ vpsrldq(xmm1, xmm1, 8, Assembler::AVX_128bit); | |
| __ vpor(xmm6, xmm6, xmm2, Assembler::AVX_128bit); | |
| __ vpshufd(xmm2, xmm1, 0x24, Assembler::AVX_128bit); | |
| __ vpcmpeqd(xmm2, xmm2, xmm12, Assembler::AVX_128bit); | |
| __ vpand(xmm2, xmm2, xmm11, Assembler::AVX_128bit); | |
| __ vpxor(xmm6, xmm6, xmm2, Assembler::AVX_128bit); | |
| __ movdqu(Address(htbl, 1 * 16), xmm6); // H * 2 | |
| __ movdqu(xmm0, xmm6); | |
| for (int i = 2; i < 9; i++) { | |
| gfmul_avx2(xmm6, xmm0); | |
| __ movdqu(Address(htbl, i * 16), xmm6); | |
| } | |
| } | |
| #define aesenc_step_avx2(t_key)\ | |
| __ aesenc(xmm1, t_key);\ | |
| __ aesenc(xmm2, t_key);\ | |
| __ aesenc(xmm3, t_key);\ | |
| __ aesenc(xmm4, t_key);\ | |
| __ aesenc(xmm5, t_key);\ | |
| __ aesenc(xmm6, t_key);\ | |
| __ aesenc(xmm7, t_key);\ | |
| __ aesenc(xmm8, t_key);\ | |
| #define ghash_step_avx2(ghdata, hkey) \ | |
| __ vpclmulqdq(xmm11, ghdata, hkey, 0x11);\ | |
| __ vpxor(xmm12, xmm12, xmm11, Assembler::AVX_128bit);\ | |
| __ vpclmulqdq(xmm11, ghdata, hkey, 0x00);\ | |
| __ vpxor(xmm15, xmm15, xmm11, Assembler::AVX_128bit);\ | |
| __ vpclmulqdq(xmm11, ghdata, hkey, 0x01);\ | |
| __ vpxor(xmm14, xmm14, xmm11, Assembler::AVX_128bit);\ | |
| __ vpclmulqdq(xmm11, ghdata, hkey, 0x10);\ | |
| __ vpxor(xmm14, xmm14, xmm11, Assembler::AVX_128bit);\ | |
| //Encrypts and hashes 8 blocks in an interleaved fashion. | |
| //Inputs: | |
| //key - key for aes operations | |
| //subkeyHtbl - table containing H constants | |
| //ctr_blockx - counter for aes operations | |
| //in - input buffer | |
| //out - output buffer | |
| //ct - ciphertext buffer | |
| //pos - holds the length processed in this method | |
| //in_order - boolean that indicates if incrementing counter without shuffling is needed | |
| //rounds - number of aes rounds calculated based on key length | |
| //xmm1-xmm8 - holds encrypted counter values | |
| //Outputs: | |
| //xmm1-xmm8 - updated encrypted counter values | |
| //ctr_blockx - updated counter value | |
| //out - updated output buffer | |
| //Temp registers: xmm0, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15, rbx | |
| void StubGenerator::ghash8_encrypt8_parallel_avx2(Register key, Register subkeyHtbl, XMMRegister ctr_blockx, Register in, | |
| Register out, Register ct, Register pos, bool in_order, Register rounds, | |
| XMMRegister xmm1, XMMRegister xmm2, XMMRegister xmm3, XMMRegister xmm4, | |
| XMMRegister xmm5, XMMRegister xmm6, XMMRegister xmm7, XMMRegister xmm8) { | |
| const XMMRegister t1 = xmm0; | |
| const XMMRegister t2 = xmm10; | |
| const XMMRegister t3 = xmm11; | |
| const XMMRegister t4 = xmm12; | |
| const XMMRegister t5 = xmm13; | |
| const XMMRegister t6 = xmm14; | |
| const XMMRegister t7 = xmm15; | |
| Label skip_reload, last_aes_rnd, aes_192, aes_256; | |
| __ movdqu(t2, xmm1); | |
| for (int i = 0; i <= 6; i++) { | |
| __ movdqu(Address(rsp, 16 * i), as_XMMRegister(i + 2)); | |
| } | |
| if (in_order) { | |
| __ vpaddd(xmm1, ctr_blockx, ExternalAddress(counter_mask_linc1_addr()), Assembler::AVX_128bit, rbx /*rscratch*/); //Increment counter by 1 | |
| __ movdqu(t5, ExternalAddress(counter_mask_linc2_addr()), rbx /*rscratch*/); | |
| __ vpaddd(xmm2, ctr_blockx, t5, Assembler::AVX_128bit); | |
| for (int rnum = 1; rnum <= 6; rnum++) { | |
| __ vpaddd(as_XMMRegister(rnum + 2), as_XMMRegister(rnum), t5, Assembler::AVX_128bit); | |
| } | |
| __ movdqu(ctr_blockx, xmm8); | |
| __ movdqu(t5, ExternalAddress(counter_shuffle_mask_addr()), rbx /*rscratch*/); | |
| for (int rnum = 1; rnum <= 8; rnum++) { | |
| __ vpshufb(as_XMMRegister(rnum), as_XMMRegister(rnum), t5, Assembler::AVX_128bit); //perform a 16Byte swap | |
| } | |
| } else { | |
| __ vpaddd(xmm1, ctr_blockx, ExternalAddress(counter_mask_linc1f_addr()), Assembler::AVX_128bit, rbx /*rscratch*/); //Increment counter by 1 | |
| __ vmovdqu(t5, ExternalAddress(counter_mask_linc2f_addr()), Assembler::AVX_128bit, rbx /*rscratch*/); | |
| __ vpaddd(xmm2, ctr_blockx, t5, Assembler::AVX_128bit); | |
| for (int rnum = 1; rnum <= 6; rnum++) { | |
| __ vpaddd(as_XMMRegister(rnum + 2), as_XMMRegister(rnum), t5, Assembler::AVX_128bit); | |
| } | |
| __ movdqu(ctr_blockx, xmm8); | |
| } | |
| load_key(t1, key, 16 * 0, rbx /*rscratch*/); | |
| for (int rnum = 1; rnum <= 8; rnum++) { | |
| __ vpxor(as_XMMRegister(rnum), as_XMMRegister(rnum), t1, Assembler::AVX_128bit); | |
| } | |
| load_key(t1, key, 16 * 1, rbx /*rscratch*/); | |
| aesenc_step_avx2(t1); | |
| load_key(t1, key, 16 * 2, rbx /*rscratch*/); | |
| aesenc_step_avx2(t1); | |
| __ movdqu(t5, (Address(subkeyHtbl, 8 * 16))); | |
| __ vpclmulqdq(t4, t2, t5, 0x11); //t4 = a1*b1 | |
| __ vpclmulqdq(t7, t2, t5, 0x00); //t7 = a0*b0 | |
| __ vpclmulqdq(t6, t2, t5, 0x01); //t6 = a1*b0 | |
| __ vpclmulqdq(t5, t2, t5, 0x10); //t5 = a0*b1 | |
| __ vpxor(t6, t6, t5, Assembler::AVX_128bit); | |
| for (int i = 3, j = 0; i <= 8; i++, j++) { | |
| load_key(t1, key, 16 * i, rbx /*rscratch*/); | |
| aesenc_step_avx2(t1); | |
| __ movdqu(t1, Address(rsp, 16 * j)); | |
| __ movdqu(t5, (Address(subkeyHtbl, (7 - j) * 16))); | |
| ghash_step_avx2(t1, t5); | |
| } | |
| load_key(t1, key, 16 * 9, rbx /*rscratch*/); | |
| aesenc_step_avx2(t1); | |
| __ movdqu(t1, Address(rsp, 16 * 6)); | |
| __ movdqu(t5, (Address(subkeyHtbl, 1 * 16))); | |
| __ vpclmulqdq(t3, t1, t5, 0x00); | |
| __ vpxor(t7, t7, t3, Assembler::AVX_128bit); | |
| __ vpclmulqdq(t3, t1, t5, 0x01); | |
| __ vpxor(t6, t6, t3, Assembler::AVX_128bit); | |
| __ vpclmulqdq(t3, t1, t5, 0x10); | |
| __ vpxor(t6, t6, t3, Assembler::AVX_128bit); | |
| __ vpclmulqdq(t3, t1, t5, 0x11); | |
| __ vpxor(t1, t4, t3, Assembler::AVX_128bit); | |
| __ vpslldq(t3, t6, 8, Assembler::AVX_128bit); //shift-L t3 2 DWs | |
| __ vpsrldq(t6, t6, 8, Assembler::AVX_128bit); //shift-R t2 2 DWs | |
| __ vpxor(t7, t7, t3, Assembler::AVX_128bit); | |
| __ vpxor(t1, t1, t6, Assembler::AVX_128bit); // accumulate the results in t1:t7 | |
| load_key(t5, key, 16 * 10, rbx /*rscratch*/); | |
| __ cmpl(rounds, 52); | |
| __ jcc(Assembler::less, last_aes_rnd); | |
| __ bind(aes_192); | |
| aesenc_step_avx2(t5); | |
| load_key(t5, key, 16 * 11, rbx /*rscratch*/); | |
| aesenc_step_avx2(t5); | |
| load_key(t5, key, 16 * 12, rbx /*rscratch*/); | |
| __ cmpl(rounds, 60); | |
| __ jcc(Assembler::less, last_aes_rnd); | |
| __ bind(aes_256); | |
| aesenc_step_avx2(t5); | |
| load_key(t5, key, 16 * 13, rbx /*rscratch*/); | |
| aesenc_step_avx2(t5); | |
| load_key(t5, key, 16 * 14, rbx /*rscratch*/); | |
| __ bind(last_aes_rnd); | |
| for (int rnum = 1; rnum <= 8; rnum++) { | |
| __ aesenclast(as_XMMRegister(rnum), t5); | |
| } | |
| for (int i = 0; i <= 7; i++) { | |
| __ movdqu(t2, Address(in, pos, Address::times_1, 16 * i)); | |
| __ vpxor(as_XMMRegister(i + 1), as_XMMRegister(i + 1), t2, Assembler::AVX_128bit); | |
| } | |
| //first phase of the reduction | |
| __ vmovdqu(t3, ExternalAddress(ghash_polynomial_reduction_addr()), Assembler::AVX_128bit, rbx /*rscratch*/); | |
| __ vpclmulqdq(t2, t3, t7, 0x01); | |
| __ vpslldq(t2, t2, 8, Assembler::AVX_128bit); //shift-L xmm2 2 DWs | |
| __ vpxor(t7, t7, t2, Assembler::AVX_128bit); //first phase of the reduction complete | |
| //Write to the Ciphertext buffer | |
| for (int i = 0; i <= 7; i++) { | |
| __ movdqu(Address(out, pos, Address::times_1, 16 * i), as_XMMRegister(i + 1)); | |
| } | |
| __ cmpptr(ct, out); | |
| __ jcc(Assembler::equal, skip_reload); | |
| for (int i = 0; i <= 7; i++) { | |
| __ movdqu(as_XMMRegister(i + 1), Address(in, pos, Address::times_1, 16 * i)); | |
| } | |
| __ bind(skip_reload); | |
| //second phase of the reduction | |
| __ vpclmulqdq(t2, t3, t7, 0x00); | |
| __ vpsrldq(t2, t2, 4, Assembler::AVX_128bit); //shift-R t2 1 DW (Shift-R only 1-DW to obtain 2-DWs shift-R) | |
| __ vpclmulqdq(t4, t3, t7, 0x10); | |
| __ vpslldq(t4, t4, 4, Assembler::AVX_128bit); //shift-L t4 1 DW (Shift-L 1-DW to obtain result with no shifts) | |
| __ vpxor(t4, t4, t2, Assembler::AVX_128bit); //second phase of the reduction complete | |
| __ vpxor(t1, t1, t4, Assembler::AVX_128bit); //the result is in t1 | |
| //perform a 16Byte swap | |
| __ movdqu(t7, ExternalAddress(counter_shuffle_mask_addr()), rbx /*rscratch*/); | |
| for (int rnum = 1; rnum <= 8; rnum++) { | |
| __ vpshufb(as_XMMRegister(rnum), as_XMMRegister(rnum), t7, Assembler::AVX_128bit); | |
| } | |
| __ vpxor(xmm1, xmm1, t1, Assembler::AVX_128bit); | |
| } | |
| //GHASH the last 8 ciphertext blocks. | |
| //Input: | |
| //subkeyHtbl - table containing H constants | |
| //Output: | |
| //xmm14 - calculated aad hash | |
| //Temp registers: xmm0, xmm10, xmm11, xmm12, xmm13, xmm15, rbx | |
| void StubGenerator::ghash_last_8_avx2(Register subkeyHtbl) { | |
| const XMMRegister t1 = xmm0; | |
| const XMMRegister t2 = xmm10; | |
| const XMMRegister t3 = xmm11; | |
| const XMMRegister t4 = xmm12; | |
| const XMMRegister t5 = xmm13; | |
| const XMMRegister t6 = xmm14; | |
| const XMMRegister t7 = xmm15; | |
| //Karatsuba Method | |
| __ movdqu(t5, Address(subkeyHtbl, 8 * 16)); | |
| __ vpshufd(t2, xmm1, 78, Assembler::AVX_128bit); | |
| __ vpshufd(t3, t5, 78, Assembler::AVX_128bit); | |
| __ vpxor(t2, t2, xmm1, Assembler::AVX_128bit); | |
| __ vpxor(t3, t3, t5, Assembler::AVX_128bit); | |
| __ vpclmulqdq(t6, xmm1, t5, 0x11); | |
| __ vpclmulqdq(t7, xmm1, t5, 0x00); | |
| __ vpclmulqdq(xmm1, t2, t3, 0x00); | |
| for (int i = 7, rnum = 2; rnum <= 8; i--, rnum++) { | |
| __ movdqu(t5, Address(subkeyHtbl, i * 16)); | |
| __ vpshufd(t2, as_XMMRegister(rnum), 78, Assembler::AVX_128bit); | |
| __ vpshufd(t3, t5, 78, Assembler::AVX_128bit); | |
| __ vpxor(t2, t2, as_XMMRegister(rnum), Assembler::AVX_128bit); | |
| __ vpxor(t3, t3, t5, Assembler::AVX_128bit); | |
| __ vpclmulqdq(t4, as_XMMRegister(rnum), t5, 0x11); | |
| __ vpxor(t6, t6, t4, Assembler::AVX_128bit); | |
| __ vpclmulqdq(t4, as_XMMRegister(rnum), t5, 0x00); | |
| __ vpxor(t7, t7, t4, Assembler::AVX_128bit); | |
| __ vpclmulqdq(t2, t2, t3, 0x00); | |
| __ vpxor(xmm1, xmm1, t2, Assembler::AVX_128bit); | |
| } | |
| __ vpxor(xmm1, xmm1, t6, Assembler::AVX_128bit); | |
| __ vpxor(t2, xmm1, t7, Assembler::AVX_128bit); | |
| __ vpslldq(t4, t2, 8, Assembler::AVX_128bit); | |
| __ vpsrldq(t2, t2, 8, Assembler::AVX_128bit); | |
| __ vpxor(t7, t7, t4, Assembler::AVX_128bit); | |
| __ vpxor(t6, t6, t2, Assembler::AVX_128bit); //<t6:t7> holds the result of the accumulated carry-less multiplications | |
| //first phase of the reduction | |
| __ movdqu(t3, ExternalAddress(ghash_polynomial_reduction_addr()), rbx /*rscratch*/); | |
| __ vpclmulqdq(t2, t3, t7, 0x01); | |
| __ vpslldq(t2, t2, 8, Assembler::AVX_128bit); // shift-L t2 2 DWs | |
| __ vpxor(t7, t7, t2, Assembler::AVX_128bit);//first phase of the reduction complete | |
| //second phase of the reduction | |
| __ vpclmulqdq(t2, t3, t7, 0x00); | |
| __ vpsrldq(t2, t2, 4, Assembler::AVX_128bit); //shift-R t2 1 DW (Shift-R only 1-DW to obtain 2-DWs shift-R) | |
| __ vpclmulqdq(t4, t3, t7, 0x10); | |
| __ vpslldq(t4, t4, 4, Assembler::AVX_128bit); //shift-L t4 1 DW (Shift-L 1-DW to obtain result with no shifts) | |
| __ vpxor(t4, t4, t2, Assembler::AVX_128bit); //second phase of the reduction complete | |
| __ vpxor(t6, t6, t4, Assembler::AVX_128bit); //the result is in t6 | |
| } | |
| //Encrypt initial number of 8 blocks | |
| //Inputs: | |
| //ctr - counter for aes operations | |
| //rounds - number of aes rounds calculated based on key length | |
| //key - key for aes operations | |
| //len - input length to be processed | |
| //in - input buffer | |
| //out - output buffer | |
| //ct - ciphertext buffer | |
| //aad_hashx - input aad hash | |
| //pos - holds the length processed in this method | |
| //Outputs: | |
| //xmm1-xmm8 - holds updated encrypted counter values | |
| //ctr - updated counter value | |
| //pos - updated position | |
| //len - updated length | |
| //out - updated output buffer | |
| //Temp registers: xmm0, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15 | |
| void StubGenerator::initial_blocks_avx2(XMMRegister ctr, Register rounds, Register key, Register len, Register in, | |
| Register out, Register ct, XMMRegister aad_hashx, Register pos) { | |
| const XMMRegister t1 = xmm12; | |
| const XMMRegister t2 = xmm13; | |
| const XMMRegister t3 = xmm14; | |
| const XMMRegister t4 = xmm15; | |
| const XMMRegister t5 = xmm11; | |
| const XMMRegister t6 = xmm10; | |
| const XMMRegister t_key = xmm0; | |
| Label skip_reload, last_aes_rnd, aes_192, aes_256; | |
| //Move AAD_HASH to temp reg t3 | |
| __ movdqu(t3, aad_hashx); | |
| //Prepare 8 counter blocks and perform rounds of AES cipher on | |
| //them, load plain/cipher text and store cipher/plain text. | |
| __ movdqu(xmm1, ctr); | |
| __ movdqu(t5, ExternalAddress(counter_mask_linc1_addr()), rbx /*rscratch*/); | |
| __ movdqu(t6, ExternalAddress(counter_mask_linc2_addr()), rbx /*rscratch*/ ); | |
| __ vpaddd(xmm2, xmm1, t5, Assembler::AVX_128bit); | |
| for (int rnum = 1; rnum <= 6; rnum++) { | |
| __ vpaddd(as_XMMRegister(rnum + 2), as_XMMRegister(rnum), t6, Assembler::AVX_128bit); | |
| } | |
| __ movdqu(ctr, xmm8); | |
| __ movdqu(t5, ExternalAddress(counter_shuffle_mask_addr()), rbx /*rscratch*/); | |
| for (int rnum = 1; rnum <= 8; rnum++) { | |
| __ vpshufb(as_XMMRegister(rnum), as_XMMRegister(rnum), t5, Assembler::AVX_128bit); //perform a 16Byte swap | |
| } | |
| load_key(t_key, key, 16 * 0, rbx /*rscratch*/); | |
| for (int rnum = 1; rnum <= 8; rnum++) { | |
| __ vpxor(as_XMMRegister(rnum), as_XMMRegister(rnum), t_key, Assembler::AVX_128bit); | |
| } | |
| for (int i = 1; i <= 9; i++) { | |
| load_key(t_key, key, 16 * i, rbx /*rscratch*/); | |
| aesenc_step_avx2(t_key); | |
| } | |
| load_key(t_key, key, 16 * 10, rbx /*rscratch*/); | |
| __ cmpl(rounds, 52); | |
| __ jcc(Assembler::less, last_aes_rnd); | |
| __ bind(aes_192); | |
| aesenc_step_avx2(t_key); | |
| load_key(t_key, key, 16 * 11, rbx /*rscratch*/); | |
| aesenc_step_avx2(t_key); | |
| load_key(t_key, key, 16 * 12, rbx /*rscratch*/); | |
| __ cmpl(rounds, 60); | |
| __ jcc(Assembler::less, last_aes_rnd); | |
| __ bind(aes_256); | |
| aesenc_step_avx2(t_key); | |
| load_key(t_key, key, 16 * 13, rbx /*rscratch*/); | |
| aesenc_step_avx2(t_key); | |
| load_key(t_key, key, 16 * 14, rbx /*rscratch*/); | |
| __ bind(last_aes_rnd); | |
| for (int rnum = 1; rnum <= 8; rnum++) { | |
| __ aesenclast(as_XMMRegister(rnum), t_key); | |
| } | |
| //XOR and store data | |
| for (int i = 0; i <= 7; i++) { | |
| __ movdqu(t1, Address(in, pos, Address::times_1, 16 * i)); | |
| __ vpxor(as_XMMRegister(i + 1), as_XMMRegister(i + 1), t1, Assembler::AVX_128bit); | |
| __ movdqu(Address(out, pos, Address::times_1, 16 * i), as_XMMRegister(i + 1)); | |
| } | |
| __ cmpptr(ct, out); | |
| __ jcc(Assembler::equal, skip_reload); | |
| for (int i = 0; i <= 7; i++) { | |
| __ movdqu(as_XMMRegister(i + 1), Address(in, pos, Address::times_1, 16 * i)); | |
| } | |
| __ bind(skip_reload); | |
| //Update len with the number of blocks processed | |
| __ subl(len, 128); | |
| __ addl(pos, 128); | |
| __ movdqu(t4, ExternalAddress(counter_shuffle_mask_addr()), rbx /*rscratch*/); | |
| for (int rnum = 1; rnum <= 8; rnum++) { | |
| __ vpshufb(as_XMMRegister(rnum), as_XMMRegister(rnum), t4, Assembler::AVX_128bit); | |
| } | |
| // Combine GHASHed value with the corresponding ciphertext | |
| __ vpxor(xmm1, xmm1, t3, Assembler::AVX_128bit); | |
| } | |
| //AES-GCM interleaved implementation | |
| //Inputs: | |
| //in - input buffer | |
| //len- message length to be processed | |
| //ct - cipher text buffer | |
| //out - output buffer | |
| //key - key for aes operations | |
| //state - address of aad hash for ghash computation | |
| //subkeyHtbl- table consisting of H constants | |
| //counter - address of counter for aes operations | |
| //Output: | |
| //(counter) - updated in memory counter value | |
| //(state) - updated in memory aad hash | |
| //rax - length processed | |
| //(out) - output buffer updated | |
| //len - updated length | |
| //Temp registers: xmm0-xmm15, r10, r15, rbx | |
| void StubGenerator::aesgcm_avx2(Register in, Register len, Register ct, Register out, Register key, | |
| Register state, Register subkeyHtbl, Register counter) { | |
| const Register pos = rax; | |
| const Register rounds = r10; | |
| const XMMRegister ctr_blockx = xmm9; | |
| const XMMRegister aad_hashx = xmm8; | |
| Label encrypt_done, encrypt_by_8_new, encrypt_by_8; | |
| //This routine should be called only for message sizes of 128 bytes or more. | |
| //Macro flow: | |
| //process 8 16 byte blocks in initial_num_blocks. | |
| //process 8 16 byte blocks at a time until all are done 'encrypt_by_8_new followed by ghash_last_8' | |
| __ xorl(pos, pos); | |
| //Generate 8 constants for htbl | |
| generateHtbl_8_block_avx2(subkeyHtbl); | |
| //Compute #rounds for AES based on the length of the key array | |
| __ movl(rounds, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); | |
| //Load and shuffle state and counter values | |
| __ movdqu(ctr_blockx, Address(counter, 0)); | |
| __ movdqu(aad_hashx, Address(state, 0)); | |
| __ vpshufb(ctr_blockx, ctr_blockx, ExternalAddress(counter_shuffle_mask_addr()), Assembler::AVX_128bit, rbx /*rscratch*/); | |
| __ vpshufb(aad_hashx, aad_hashx, ExternalAddress(ghash_long_swap_mask_addr()), Assembler::AVX_128bit, rbx /*rscratch*/); | |
| initial_blocks_avx2(ctr_blockx, rounds, key, len, in, out, ct, aad_hashx, pos); | |
| //We need at least 128 bytes to proceed further. | |
| __ cmpl(len, 128); | |
| __ jcc(Assembler::less, encrypt_done); | |
| //in_order vs. out_order is an optimization to increment the counter without shuffling | |
| //it back into little endian. r15d keeps track of when we need to increment in order so | |
| //that the carry is handled correctly. | |
| __ movdl(r15, ctr_blockx); | |
| __ andl(r15, 255); | |
| __ vpshufb(ctr_blockx, ctr_blockx, ExternalAddress(counter_shuffle_mask_addr()), Assembler::AVX_128bit, rbx /*rscratch*/); | |
| __ bind(encrypt_by_8_new); | |
| __ cmpl(r15, 255 - 8); | |
| __ jcc(Assembler::greater, encrypt_by_8); | |
| __ addb(r15, 8); | |
| ghash8_encrypt8_parallel_avx2(key, subkeyHtbl, ctr_blockx, in, out, ct, pos, false, rounds, | |
| xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm8); | |
| __ addl(pos, 128); | |
| __ subl(len, 128); | |
| __ cmpl(len, 128); | |
| __ jcc(Assembler::greaterEqual, encrypt_by_8_new); | |
| __ vpshufb(ctr_blockx, ctr_blockx, ExternalAddress(counter_shuffle_mask_addr()), Assembler::AVX_128bit, rbx /*rscratch*/); | |
| __ jmp(encrypt_done); | |
| __ bind(encrypt_by_8); | |
| __ vpshufb(ctr_blockx, ctr_blockx, ExternalAddress(counter_shuffle_mask_addr()), Assembler::AVX_128bit, rbx /*rscratch*/); | |
| __ addb(r15, 8); | |
| ghash8_encrypt8_parallel_avx2(key, subkeyHtbl, ctr_blockx, in, out, ct, pos, true, rounds, | |
| xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm8); | |
| __ vpshufb(ctr_blockx, ctr_blockx, ExternalAddress(counter_shuffle_mask_addr()), Assembler::AVX_128bit, rbx /*rscratch*/); | |
| __ addl(pos, 128); | |
| __ subl(len, 128); | |
| __ cmpl(len, 128); | |
| __ jcc(Assembler::greaterEqual, encrypt_by_8_new); | |
| __ vpshufb(ctr_blockx, ctr_blockx, ExternalAddress(counter_shuffle_mask_addr()), Assembler::AVX_128bit, rbx /*rscratch*/); | |
| __ bind(encrypt_done); | |
| ghash_last_8_avx2(subkeyHtbl); | |
| __ vpaddd(ctr_blockx, ctr_blockx, ExternalAddress(counter_mask_linc1_addr()), Assembler::AVX_128bit, rbx /*rscratch*/); | |
| __ vpshufb(ctr_blockx, ctr_blockx, ExternalAddress(counter_shuffle_mask_addr()), Assembler::AVX_128bit, rbx /*rscratch*/); | |
| __ movdqu(Address(counter, 0), ctr_blockx); //current_counter = xmm9 | |
| __ vpshufb(xmm14, xmm14, ExternalAddress(ghash_long_swap_mask_addr()), Assembler::AVX_128bit, rbx /*rscratch*/); | |
| __ movdqu(Address(state, 0), xmm14); //aad hash = xmm14 | |
| //Xor out round keys | |
| __ vpxor(xmm0, xmm0, xmm0, Assembler::AVX_128bit); | |
| __ vpxor(xmm13, xmm13, xmm13, Assembler::AVX_128bit); | |
| } | |
| #undef __ |