This change adds AES and GHASH assembly from upstream, with the aim of speeding up AES-GCM. The PPC64LE assembly matches the interface of the ARMv8 assembly so I've changed the prefix of both sets of asm functions to be the same ("aes_hw_"). Otherwise, the new assmebly files and Perlasm match exactly those from upstream's c536b6be1a (from their master branch). Before: Did 1879000 AES-128-GCM (16 bytes) seal operations in 1000428us (1878196.1 ops/sec): 30.1 MB/s Did 61000 AES-128-GCM (1350 bytes) seal operations in 1006660us (60596.4 ops/sec): 81.8 MB/s Did 11000 AES-128-GCM (8192 bytes) seal operations in 1072649us (10255.0 ops/sec): 84.0 MB/s Did 1665000 AES-256-GCM (16 bytes) seal operations in 1000591us (1664016.6 ops/sec): 26.6 MB/s Did 52000 AES-256-GCM (1350 bytes) seal operations in 1006971us (51640.0 ops/sec): 69.7 MB/s Did 8840 AES-256-GCM (8192 bytes) seal operations in 1013294us (8724.0 ops/sec): 71.5 MB/s After: Did 4994000 AES-128-GCM (16 bytes) seal operations in 1000017us (4993915.1 ops/sec): 79.9 MB/s Did 1389000 AES-128-GCM (1350 bytes) seal operations in 1000073us (1388898.6 ops/sec): 1875.0 MB/s Did 319000 AES-128-GCM (8192 bytes) seal operations in 1000101us (318967.8 ops/sec): 2613.0 MB/s Did 4668000 AES-256-GCM (16 bytes) seal operations in 1000149us (4667304.6 ops/sec): 74.7 MB/s Did 1202000 AES-256-GCM (1350 bytes) seal operations in 1000646us (1201224.0 ops/sec): 1621.7 MB/s Did 269000 AES-256-GCM (8192 bytes) seal operations in 1002804us (268247.8 ops/sec): 2197.5 MB/s Change-Id: Id848562bd4e1aa79a4683012501dfa5e6c08cfcc Reviewed-on: https://boringssl-review.googlesource.com/11262 Reviewed-by: Adam Langley <agl@google.com> Commit-Queue: Adam Langley <agl@google.com> CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>kris/onging/CECPQ3_patch15
@@ -17,6 +17,8 @@ elseif(UNIX) | |||||
elseif (${ARCH} STREQUAL "x86") | elseif (${ARCH} STREQUAL "x86") | ||||
set(PERLASM_FLAGS "-fPIC -DOPENSSL_IA32_SSE2") | set(PERLASM_FLAGS "-fPIC -DOPENSSL_IA32_SSE2") | ||||
set(PERLASM_STYLE elf) | set(PERLASM_STYLE elf) | ||||
elseif (${ARCH} STREQUAL "ppc64le") | |||||
set(PERLASM_STYLE ppc64le) | |||||
else() | else() | ||||
set(PERLASM_STYLE elf) | set(PERLASM_STYLE elf) | ||||
endif() | endif() | ||||
@@ -45,6 +47,7 @@ function(perlasm dest src) | |||||
DEPENDS | DEPENDS | ||||
${src} | ${src} | ||||
${PROJECT_SOURCE_DIR}/crypto/perlasm/arm-xlate.pl | ${PROJECT_SOURCE_DIR}/crypto/perlasm/arm-xlate.pl | ||||
${PROJECT_SOURCE_DIR}/crypto/perlasm/ppc-xlate.pl | |||||
${PROJECT_SOURCE_DIR}/crypto/perlasm/x86_64-xlate.pl | ${PROJECT_SOURCE_DIR}/crypto/perlasm/x86_64-xlate.pl | ||||
${PROJECT_SOURCE_DIR}/crypto/perlasm/x86asm.pl | ${PROJECT_SOURCE_DIR}/crypto/perlasm/x86asm.pl | ||||
${PROJECT_SOURCE_DIR}/crypto/perlasm/x86gas.pl | ${PROJECT_SOURCE_DIR}/crypto/perlasm/x86gas.pl | ||||
@@ -116,6 +119,7 @@ add_library( | |||||
cpu-arm.c | cpu-arm.c | ||||
cpu-arm-linux.c | cpu-arm-linux.c | ||||
cpu-intel.c | cpu-intel.c | ||||
cpu-ppc64le.c | |||||
crypto.c | crypto.c | ||||
ex_data.c | ex_data.c | ||||
mem.c | mem.c | ||||
@@ -39,6 +39,14 @@ if (${ARCH} STREQUAL "aarch64") | |||||
) | ) | ||||
endif() | endif() | ||||
if (${ARCH} STREQUAL "ppc64le") | |||||
set( | |||||
AES_ARCH_SOURCES | |||||
aesp8-ppc.${ASM_EXT} | |||||
) | |||||
endif() | |||||
add_library( | add_library( | ||||
aes | aes | ||||
@@ -60,6 +68,7 @@ perlasm(aesni-x86.${ASM_EXT} asm/aesni-x86.pl) | |||||
perlasm(aes-armv4.${ASM_EXT} asm/aes-armv4.pl) | perlasm(aes-armv4.${ASM_EXT} asm/aes-armv4.pl) | ||||
perlasm(bsaes-armv7.${ASM_EXT} asm/bsaes-armv7.pl) | perlasm(bsaes-armv7.${ASM_EXT} asm/bsaes-armv7.pl) | ||||
perlasm(aesv8-armx.${ASM_EXT} asm/aesv8-armx.pl) | perlasm(aesv8-armx.${ASM_EXT} asm/aesv8-armx.pl) | ||||
perlasm(aesp8-ppc.${ASM_EXT} asm/aesp8-ppc.pl) | |||||
add_executable( | add_executable( | ||||
aes_test | aes_test | ||||
@@ -42,7 +42,7 @@ die "can't locate arm-xlate.pl"; | |||||
open OUT,"| \"$^X\" $xlate $flavour $output"; | open OUT,"| \"$^X\" $xlate $flavour $output"; | ||||
*STDOUT=*OUT; | *STDOUT=*OUT; | ||||
$prefix="aes_v8"; | |||||
$prefix="aes_hw"; | |||||
$code=<<___; | $code=<<___; | ||||
#include <openssl/arm_arch.h> | #include <openssl/arm_arch.h> | ||||
@@ -125,18 +125,15 @@ static int hwaes_capable(void) { | |||||
return CRYPTO_is_ARMv8_AES_capable(); | return CRYPTO_is_ARMv8_AES_capable(); | ||||
} | } | ||||
int aes_v8_set_encrypt_key(const uint8_t *user_key, const int bits, | |||||
AES_KEY *key); | |||||
int aes_v8_set_decrypt_key(const uint8_t *user_key, const int bits, | |||||
AES_KEY *key); | |||||
void aes_v8_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); | |||||
void aes_v8_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); | |||||
void aes_v8_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length, | |||||
const AES_KEY *key, uint8_t *ivec, const int enc); | |||||
void aes_v8_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t len, | |||||
const AES_KEY *key, const uint8_t ivec[16]); | |||||
#elif !defined(OPENSSL_NO_ASM) && defined(OPENSSL_PPC64LE) | |||||
#define HWAES | |||||
static int hwaes_capable(void) { | |||||
return CRYPTO_is_PPC64LE_vcrypto_capable(); | |||||
} | |||||
#endif /* OPENSSL_PPC64LE */ | |||||
#endif /* OPENSSL_ARM */ | |||||
#if defined(BSAES) | #if defined(BSAES) | ||||
/* On platforms where BSAES gets defined (just above), then these functions are | /* On platforms where BSAES gets defined (just above), then these functions are | ||||
@@ -202,39 +199,50 @@ static void vpaes_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length, | |||||
} | } | ||||
#endif | #endif | ||||
#if !defined(HWAES) | |||||
#if defined(HWAES) | |||||
int aes_hw_set_encrypt_key(const uint8_t *user_key, const int bits, | |||||
AES_KEY *key); | |||||
int aes_hw_set_decrypt_key(const uint8_t *user_key, const int bits, | |||||
AES_KEY *key); | |||||
void aes_hw_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); | |||||
void aes_hw_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); | |||||
void aes_hw_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length, | |||||
const AES_KEY *key, uint8_t *ivec, const int enc); | |||||
void aes_hw_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t len, | |||||
const AES_KEY *key, const uint8_t ivec[16]); | |||||
#else | |||||
/* If HWAES isn't defined then we provide dummy functions for each of the hwaes | /* If HWAES isn't defined then we provide dummy functions for each of the hwaes | ||||
* functions. */ | * functions. */ | ||||
static int hwaes_capable(void) { | static int hwaes_capable(void) { | ||||
return 0; | return 0; | ||||
} | } | ||||
static int aes_v8_set_encrypt_key(const uint8_t *user_key, int bits, | |||||
static int aes_hw_set_encrypt_key(const uint8_t *user_key, int bits, | |||||
AES_KEY *key) { | AES_KEY *key) { | ||||
abort(); | abort(); | ||||
} | } | ||||
static int aes_v8_set_decrypt_key(const uint8_t *user_key, int bits, | |||||
static int aes_hw_set_decrypt_key(const uint8_t *user_key, int bits, | |||||
AES_KEY *key) { | AES_KEY *key) { | ||||
abort(); | abort(); | ||||
} | } | ||||
static void aes_v8_encrypt(const uint8_t *in, uint8_t *out, | |||||
static void aes_hw_encrypt(const uint8_t *in, uint8_t *out, | |||||
const AES_KEY *key) { | const AES_KEY *key) { | ||||
abort(); | abort(); | ||||
} | } | ||||
static void aes_v8_decrypt(const uint8_t *in, uint8_t *out, | |||||
static void aes_hw_decrypt(const uint8_t *in, uint8_t *out, | |||||
const AES_KEY *key) { | const AES_KEY *key) { | ||||
abort(); | abort(); | ||||
} | } | ||||
static void aes_v8_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length, | |||||
static void aes_hw_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length, | |||||
const AES_KEY *key, uint8_t *ivec, int enc) { | const AES_KEY *key, uint8_t *ivec, int enc) { | ||||
abort(); | abort(); | ||||
} | } | ||||
static void aes_v8_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, | |||||
static void aes_hw_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, | |||||
size_t len, const AES_KEY *key, | size_t len, const AES_KEY *key, | ||||
const uint8_t ivec[16]) { | const uint8_t ivec[16]) { | ||||
abort(); | abort(); | ||||
@@ -281,11 +289,11 @@ static int aes_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key, | |||||
mode = ctx->cipher->flags & EVP_CIPH_MODE_MASK; | mode = ctx->cipher->flags & EVP_CIPH_MODE_MASK; | ||||
if ((mode == EVP_CIPH_ECB_MODE || mode == EVP_CIPH_CBC_MODE) && !enc) { | if ((mode == EVP_CIPH_ECB_MODE || mode == EVP_CIPH_CBC_MODE) && !enc) { | ||||
if (hwaes_capable()) { | if (hwaes_capable()) { | ||||
ret = aes_v8_set_decrypt_key(key, ctx->key_len * 8, &dat->ks.ks); | |||||
dat->block = (block128_f)aes_v8_decrypt; | |||||
ret = aes_hw_set_decrypt_key(key, ctx->key_len * 8, &dat->ks.ks); | |||||
dat->block = (block128_f)aes_hw_decrypt; | |||||
dat->stream.cbc = NULL; | dat->stream.cbc = NULL; | ||||
if (mode == EVP_CIPH_CBC_MODE) { | if (mode == EVP_CIPH_CBC_MODE) { | ||||
dat->stream.cbc = (cbc128_f)aes_v8_cbc_encrypt; | |||||
dat->stream.cbc = (cbc128_f)aes_hw_cbc_encrypt; | |||||
} | } | ||||
} else if (bsaes_capable() && mode == EVP_CIPH_CBC_MODE) { | } else if (bsaes_capable() && mode == EVP_CIPH_CBC_MODE) { | ||||
ret = AES_set_decrypt_key(key, ctx->key_len * 8, &dat->ks.ks); | ret = AES_set_decrypt_key(key, ctx->key_len * 8, &dat->ks.ks); | ||||
@@ -303,13 +311,13 @@ static int aes_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key, | |||||
mode == EVP_CIPH_CBC_MODE ? (cbc128_f)AES_cbc_encrypt : NULL; | mode == EVP_CIPH_CBC_MODE ? (cbc128_f)AES_cbc_encrypt : NULL; | ||||
} | } | ||||
} else if (hwaes_capable()) { | } else if (hwaes_capable()) { | ||||
ret = aes_v8_set_encrypt_key(key, ctx->key_len * 8, &dat->ks.ks); | |||||
dat->block = (block128_f)aes_v8_encrypt; | |||||
ret = aes_hw_set_encrypt_key(key, ctx->key_len * 8, &dat->ks.ks); | |||||
dat->block = (block128_f)aes_hw_encrypt; | |||||
dat->stream.cbc = NULL; | dat->stream.cbc = NULL; | ||||
if (mode == EVP_CIPH_CBC_MODE) { | if (mode == EVP_CIPH_CBC_MODE) { | ||||
dat->stream.cbc = (cbc128_f)aes_v8_cbc_encrypt; | |||||
dat->stream.cbc = (cbc128_f)aes_hw_cbc_encrypt; | |||||
} else if (mode == EVP_CIPH_CTR_MODE) { | } else if (mode == EVP_CIPH_CTR_MODE) { | ||||
dat->stream.ctr = (ctr128_f)aes_v8_ctr32_encrypt_blocks; | |||||
dat->stream.ctr = (ctr128_f)aes_hw_ctr32_encrypt_blocks; | |||||
} | } | ||||
} else if (bsaes_capable() && mode == EVP_CIPH_CTR_MODE) { | } else if (bsaes_capable() && mode == EVP_CIPH_CTR_MODE) { | ||||
ret = AES_set_encrypt_key(key, ctx->key_len * 8, &dat->ks.ks); | ret = AES_set_encrypt_key(key, ctx->key_len * 8, &dat->ks.ks); | ||||
@@ -406,14 +414,14 @@ static ctr128_f aes_ctr_set_key(AES_KEY *aes_key, GCM128_CONTEXT *gcm_ctx, | |||||
} | } | ||||
if (hwaes_capable()) { | if (hwaes_capable()) { | ||||
aes_v8_set_encrypt_key(key, key_len * 8, aes_key); | |||||
aes_hw_set_encrypt_key(key, key_len * 8, aes_key); | |||||
if (gcm_ctx != NULL) { | if (gcm_ctx != NULL) { | ||||
CRYPTO_gcm128_init(gcm_ctx, aes_key, (block128_f)aes_v8_encrypt); | |||||
CRYPTO_gcm128_init(gcm_ctx, aes_key, (block128_f)aes_hw_encrypt); | |||||
} | } | ||||
if (out_block) { | if (out_block) { | ||||
*out_block = (block128_f) aes_v8_encrypt; | |||||
*out_block = (block128_f) aes_hw_encrypt; | |||||
} | } | ||||
return (ctr128_f)aes_v8_ctr32_encrypt_blocks; | |||||
return (ctr128_f)aes_hw_ctr32_encrypt_blocks; | |||||
} | } | ||||
if (bsaes_capable()) { | if (bsaes_capable()) { | ||||
@@ -0,0 +1,40 @@ | |||||
/* Copyright (c) 2016, Google Inc. | |||||
* | |||||
* Permission to use, copy, modify, and/or distribute this software for any | |||||
* purpose with or without fee is hereby granted, provided that the above | |||||
* copyright notice and this permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | |||||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | |||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ | |||||
#include <openssl/cpu.h> | |||||
#if defined(OPENSSL_PPC64LE) | |||||
#include <sys/auxv.h> | |||||
#include "internal.h" | |||||
#if !defined(PPC_FEATURE2_HAS_VCRYPTO) | |||||
/* PPC_FEATURE2_HAS_VCRYPTO was taken from section 4.1.2.3 of the “OpenPOWER | |||||
* ABI for Linux Supplement”. */ | |||||
#define PPC_FEATURE2_HAS_VCRYPTO 0x02000000 | |||||
#endif | |||||
static unsigned long g_ppc64le_hwcap2 = 0; | |||||
void OPENSSL_cpuid_setup(void) { | |||||
g_ppc64le_hwcap2 = getauxval(AT_HWCAP2); | |||||
} | |||||
int CRYPTO_is_PPC64LE_vcrypto_capable(void) { | |||||
return (g_ppc64le_hwcap2 & PPC_FEATURE2_HAS_VCRYPTO) != 0; | |||||
} | |||||
#endif /* OPENSSL_PPC64LE */ |
@@ -21,9 +21,11 @@ | |||||
#if !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_STATIC_ARMCAP) && \ | #if !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_STATIC_ARMCAP) && \ | ||||
(defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || \ | (defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || \ | ||||
defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)) | |||||
/* x86, x86_64 and the ARMs need to record the result of a cpuid call for the | |||||
* asm to work correctly, unless compiled without asm code. */ | |||||
defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64) || \ | |||||
defined(OPENSSL_PPC64LE)) | |||||
/* x86, x86_64, the ARMs and ppc64le need to record the result of a | |||||
* cpuid/getauxval call for the asm to work correctly, unless compiled without | |||||
* asm code. */ | |||||
#define NEED_CPUID | #define NEED_CPUID | ||||
#else | #else | ||||
@@ -141,8 +141,8 @@ extern "C" { | |||||
#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || defined(OPENSSL_ARM) || \ | #if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || defined(OPENSSL_ARM) || \ | ||||
defined(OPENSSL_AARCH64) | |||||
/* OPENSSL_cpuid_setup initializes OPENSSL_ia32cap_P. */ | |||||
defined(OPENSSL_AARCH64) || defined(OPENSSL_PPC64LE) | |||||
/* OPENSSL_cpuid_setup initializes the platform-specific feature cache. */ | |||||
void OPENSSL_cpuid_setup(void); | void OPENSSL_cpuid_setup(void); | ||||
#endif | #endif | ||||
@@ -34,6 +34,14 @@ if (${ARCH} STREQUAL "aarch64") | |||||
) | ) | ||||
endif() | endif() | ||||
if (${ARCH} STREQUAL "ppc64le") | |||||
set( | |||||
MODES_ARCH_SOURCES | |||||
ghashp8-ppc.${ASM_EXT} | |||||
) | |||||
endif() | |||||
add_library( | add_library( | ||||
modes | modes | ||||
@@ -53,6 +61,7 @@ perlasm(ghash-x86_64.${ASM_EXT} asm/ghash-x86_64.pl) | |||||
perlasm(ghash-x86.${ASM_EXT} asm/ghash-x86.pl) | perlasm(ghash-x86.${ASM_EXT} asm/ghash-x86.pl) | ||||
perlasm(ghash-armv4.${ASM_EXT} asm/ghash-armv4.pl) | perlasm(ghash-armv4.${ASM_EXT} asm/ghash-armv4.pl) | ||||
perlasm(ghashv8-armx.${ASM_EXT} asm/ghashv8-armx.pl) | perlasm(ghashv8-armx.${ASM_EXT} asm/ghashv8-armx.pl) | ||||
perlasm(ghashp8-ppc.${ASM_EXT} asm/ghashp8-ppc.pl) | |||||
add_executable( | add_executable( | ||||
gcm_test | gcm_test | ||||
@@ -0,0 +1,670 @@ | |||||
#! /usr/bin/env perl | |||||
# Copyright 2014-2016 The OpenSSL Project Authors. All Rights Reserved. | |||||
# | |||||
# Licensed under the OpenSSL license (the "License"). You may not use | |||||
# this file except in compliance with the License. You can obtain a copy | |||||
# in the file LICENSE in the source distribution or at | |||||
# https://www.openssl.org/source/license.html | |||||
# | |||||
# ==================================================================== | |||||
# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL | |||||
# project. The module is, however, dual licensed under OpenSSL and | |||||
# CRYPTOGAMS licenses depending on where you obtain it. For further | |||||
# details see http://www.openssl.org/~appro/cryptogams/. | |||||
# ==================================================================== | |||||
# | |||||
# GHASH for for PowerISA v2.07. | |||||
# | |||||
# July 2014 | |||||
# | |||||
# Accurate performance measurements are problematic, because it's | |||||
# always virtualized setup with possibly throttled processor. | |||||
# Relative comparison is therefore more informative. This initial | |||||
# version is ~2.1x slower than hardware-assisted AES-128-CTR, ~12x | |||||
# faster than "4-bit" integer-only compiler-generated 64-bit code. | |||||
# "Initial version" means that there is room for futher improvement. | |||||
# May 2016 | |||||
# | |||||
# 2x aggregated reduction improves performance by 50% (resulting | |||||
# performance on POWER8 is 1 cycle per processed byte), and 4x | |||||
# aggregated reduction - by 170% or 2.7x (resulting in 0.55 cpb). | |||||
$flavour=shift; | |||||
$output =shift; | |||||
if ($flavour =~ /64/) { | |||||
$SIZE_T=8; | |||||
$LRSAVE=2*$SIZE_T; | |||||
$STU="stdu"; | |||||
$POP="ld"; | |||||
$PUSH="std"; | |||||
$UCMP="cmpld"; | |||||
$SHRI="srdi"; | |||||
} elsif ($flavour =~ /32/) { | |||||
$SIZE_T=4; | |||||
$LRSAVE=$SIZE_T; | |||||
$STU="stwu"; | |||||
$POP="lwz"; | |||||
$PUSH="stw"; | |||||
$UCMP="cmplw"; | |||||
$SHRI="srwi"; | |||||
} else { die "nonsense $flavour"; } | |||||
$sp="r1"; | |||||
$FRAME=6*$SIZE_T+13*16; # 13*16 is for v20-v31 offload | |||||
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; | |||||
( $xlate="${dir}ppc-xlate.pl" and -f $xlate ) or | |||||
( $xlate="${dir}../../perlasm/ppc-xlate.pl" and -f $xlate) or | |||||
die "can't locate ppc-xlate.pl"; | |||||
open STDOUT,"| $^X $xlate $flavour $output" || die "can't call $xlate: $!"; | |||||
my ($Xip,$Htbl,$inp,$len)=map("r$_",(3..6)); # argument block | |||||
my ($Xl,$Xm,$Xh,$IN)=map("v$_",(0..3)); | |||||
my ($zero,$t0,$t1,$t2,$xC2,$H,$Hh,$Hl,$lemask)=map("v$_",(4..12)); | |||||
my ($Xl1,$Xm1,$Xh1,$IN1,$H2,$H2h,$H2l)=map("v$_",(13..19)); | |||||
my $vrsave="r12"; | |||||
$code=<<___; | |||||
.machine "any" | |||||
.text | |||||
.globl .gcm_init_p8 | |||||
.align 5 | |||||
.gcm_init_p8: | |||||
li r0,-4096 | |||||
li r8,0x10 | |||||
mfspr $vrsave,256 | |||||
li r9,0x20 | |||||
mtspr 256,r0 | |||||
li r10,0x30 | |||||
lvx_u $H,0,r4 # load H | |||||
vspltisb $xC2,-16 # 0xf0 | |||||
vspltisb $t0,1 # one | |||||
vaddubm $xC2,$xC2,$xC2 # 0xe0 | |||||
vxor $zero,$zero,$zero | |||||
vor $xC2,$xC2,$t0 # 0xe1 | |||||
vsldoi $xC2,$xC2,$zero,15 # 0xe1... | |||||
vsldoi $t1,$zero,$t0,1 # ...1 | |||||
vaddubm $xC2,$xC2,$xC2 # 0xc2... | |||||
vspltisb $t2,7 | |||||
vor $xC2,$xC2,$t1 # 0xc2....01 | |||||
vspltb $t1,$H,0 # most significant byte | |||||
vsl $H,$H,$t0 # H<<=1 | |||||
vsrab $t1,$t1,$t2 # broadcast carry bit | |||||
vand $t1,$t1,$xC2 | |||||
vxor $IN,$H,$t1 # twisted H | |||||
vsldoi $H,$IN,$IN,8 # twist even more ... | |||||
vsldoi $xC2,$zero,$xC2,8 # 0xc2.0 | |||||
vsldoi $Hl,$zero,$H,8 # ... and split | |||||
vsldoi $Hh,$H,$zero,8 | |||||
stvx_u $xC2,0,r3 # save pre-computed table | |||||
stvx_u $Hl,r8,r3 | |||||
li r8,0x40 | |||||
stvx_u $H, r9,r3 | |||||
li r9,0x50 | |||||
stvx_u $Hh,r10,r3 | |||||
li r10,0x60 | |||||
vpmsumd $Xl,$IN,$Hl # H.lo·H.lo | |||||
vpmsumd $Xm,$IN,$H # H.hi·H.lo+H.lo·H.hi | |||||
vpmsumd $Xh,$IN,$Hh # H.hi·H.hi | |||||
vpmsumd $t2,$Xl,$xC2 # 1st reduction phase | |||||
vsldoi $t0,$Xm,$zero,8 | |||||
vsldoi $t1,$zero,$Xm,8 | |||||
vxor $Xl,$Xl,$t0 | |||||
vxor $Xh,$Xh,$t1 | |||||
vsldoi $Xl,$Xl,$Xl,8 | |||||
vxor $Xl,$Xl,$t2 | |||||
vsldoi $t1,$Xl,$Xl,8 # 2nd reduction phase | |||||
vpmsumd $Xl,$Xl,$xC2 | |||||
vxor $t1,$t1,$Xh | |||||
vxor $IN1,$Xl,$t1 | |||||
vsldoi $H2,$IN1,$IN1,8 | |||||
vsldoi $H2l,$zero,$H2,8 | |||||
vsldoi $H2h,$H2,$zero,8 | |||||
stvx_u $H2l,r8,r3 # save H^2 | |||||
li r8,0x70 | |||||
stvx_u $H2,r9,r3 | |||||
li r9,0x80 | |||||
stvx_u $H2h,r10,r3 | |||||
li r10,0x90 | |||||
___ | |||||
{ | |||||
my ($t4,$t5,$t6) = ($Hl,$H,$Hh); | |||||
$code.=<<___; | |||||
vpmsumd $Xl,$IN,$H2l # H.lo·H^2.lo | |||||
vpmsumd $Xl1,$IN1,$H2l # H^2.lo·H^2.lo | |||||
vpmsumd $Xm,$IN,$H2 # H.hi·H^2.lo+H.lo·H^2.hi | |||||
vpmsumd $Xm1,$IN1,$H2 # H^2.hi·H^2.lo+H^2.lo·H^2.hi | |||||
vpmsumd $Xh,$IN,$H2h # H.hi·H^2.hi | |||||
vpmsumd $Xh1,$IN1,$H2h # H^2.hi·H^2.hi | |||||
vpmsumd $t2,$Xl,$xC2 # 1st reduction phase | |||||
vpmsumd $t6,$Xl1,$xC2 # 1st reduction phase | |||||
vsldoi $t0,$Xm,$zero,8 | |||||
vsldoi $t1,$zero,$Xm,8 | |||||
vsldoi $t4,$Xm1,$zero,8 | |||||
vsldoi $t5,$zero,$Xm1,8 | |||||
vxor $Xl,$Xl,$t0 | |||||
vxor $Xh,$Xh,$t1 | |||||
vxor $Xl1,$Xl1,$t4 | |||||
vxor $Xh1,$Xh1,$t5 | |||||
vsldoi $Xl,$Xl,$Xl,8 | |||||
vsldoi $Xl1,$Xl1,$Xl1,8 | |||||
vxor $Xl,$Xl,$t2 | |||||
vxor $Xl1,$Xl1,$t6 | |||||
vsldoi $t1,$Xl,$Xl,8 # 2nd reduction phase | |||||
vsldoi $t5,$Xl1,$Xl1,8 # 2nd reduction phase | |||||
vpmsumd $Xl,$Xl,$xC2 | |||||
vpmsumd $Xl1,$Xl1,$xC2 | |||||
vxor $t1,$t1,$Xh | |||||
vxor $t5,$t5,$Xh1 | |||||
vxor $Xl,$Xl,$t1 | |||||
vxor $Xl1,$Xl1,$t5 | |||||
vsldoi $H,$Xl,$Xl,8 | |||||
vsldoi $H2,$Xl1,$Xl1,8 | |||||
vsldoi $Hl,$zero,$H,8 | |||||
vsldoi $Hh,$H,$zero,8 | |||||
vsldoi $H2l,$zero,$H2,8 | |||||
vsldoi $H2h,$H2,$zero,8 | |||||
stvx_u $Hl,r8,r3 # save H^3 | |||||
li r8,0xa0 | |||||
stvx_u $H,r9,r3 | |||||
li r9,0xb0 | |||||
stvx_u $Hh,r10,r3 | |||||
li r10,0xc0 | |||||
stvx_u $H2l,r8,r3 # save H^4 | |||||
stvx_u $H2,r9,r3 | |||||
stvx_u $H2h,r10,r3 | |||||
mtspr 256,$vrsave | |||||
blr | |||||
.long 0 | |||||
.byte 0,12,0x14,0,0,0,2,0 | |||||
.long 0 | |||||
.size .gcm_init_p8,.-.gcm_init_p8 | |||||
___ | |||||
} | |||||
$code.=<<___; | |||||
.globl .gcm_gmult_p8 | |||||
.align 5 | |||||
.gcm_gmult_p8: | |||||
lis r0,0xfff8 | |||||
li r8,0x10 | |||||
mfspr $vrsave,256 | |||||
li r9,0x20 | |||||
mtspr 256,r0 | |||||
li r10,0x30 | |||||
lvx_u $IN,0,$Xip # load Xi | |||||
lvx_u $Hl,r8,$Htbl # load pre-computed table | |||||
le?lvsl $lemask,r0,r0 | |||||
lvx_u $H, r9,$Htbl | |||||
le?vspltisb $t0,0x07 | |||||
lvx_u $Hh,r10,$Htbl | |||||
le?vxor $lemask,$lemask,$t0 | |||||
lvx_u $xC2,0,$Htbl | |||||
le?vperm $IN,$IN,$IN,$lemask | |||||
vxor $zero,$zero,$zero | |||||
vpmsumd $Xl,$IN,$Hl # H.lo·Xi.lo | |||||
vpmsumd $Xm,$IN,$H # H.hi·Xi.lo+H.lo·Xi.hi | |||||
vpmsumd $Xh,$IN,$Hh # H.hi·Xi.hi | |||||
vpmsumd $t2,$Xl,$xC2 # 1st reduction phase | |||||
vsldoi $t0,$Xm,$zero,8 | |||||
vsldoi $t1,$zero,$Xm,8 | |||||
vxor $Xl,$Xl,$t0 | |||||
vxor $Xh,$Xh,$t1 | |||||
vsldoi $Xl,$Xl,$Xl,8 | |||||
vxor $Xl,$Xl,$t2 | |||||
vsldoi $t1,$Xl,$Xl,8 # 2nd reduction phase | |||||
vpmsumd $Xl,$Xl,$xC2 | |||||
vxor $t1,$t1,$Xh | |||||
vxor $Xl,$Xl,$t1 | |||||
le?vperm $Xl,$Xl,$Xl,$lemask | |||||
stvx_u $Xl,0,$Xip # write out Xi | |||||
mtspr 256,$vrsave | |||||
blr | |||||
.long 0 | |||||
.byte 0,12,0x14,0,0,0,2,0 | |||||
.long 0 | |||||
.size .gcm_gmult_p8,.-.gcm_gmult_p8 | |||||
.globl .gcm_ghash_p8 | |||||
.align 5 | |||||
.gcm_ghash_p8: | |||||
li r0,-4096 | |||||
li r8,0x10 | |||||
mfspr $vrsave,256 | |||||
li r9,0x20 | |||||
mtspr 256,r0 | |||||
li r10,0x30 | |||||
lvx_u $Xl,0,$Xip # load Xi | |||||
lvx_u $Hl,r8,$Htbl # load pre-computed table | |||||
li r8,0x40 | |||||
le?lvsl $lemask,r0,r0 | |||||
lvx_u $H, r9,$Htbl | |||||
li r9,0x50 | |||||
le?vspltisb $t0,0x07 | |||||
lvx_u $Hh,r10,$Htbl | |||||
li r10,0x60 | |||||
le?vxor $lemask,$lemask,$t0 | |||||
lvx_u $xC2,0,$Htbl | |||||
le?vperm $Xl,$Xl,$Xl,$lemask | |||||
vxor $zero,$zero,$zero | |||||
${UCMP}i $len,64 | |||||
bge Lgcm_ghash_p8_4x | |||||
lvx_u $IN,0,$inp | |||||
addi $inp,$inp,16 | |||||
subic. $len,$len,16 | |||||
le?vperm $IN,$IN,$IN,$lemask | |||||
vxor $IN,$IN,$Xl | |||||
beq Lshort | |||||
lvx_u $H2l,r8,$Htbl # load H^2 | |||||
li r8,16 | |||||
lvx_u $H2, r9,$Htbl | |||||
add r9,$inp,$len # end of input | |||||
lvx_u $H2h,r10,$Htbl | |||||
be?b Loop_2x | |||||
.align 5 | |||||
Loop_2x: | |||||
lvx_u $IN1,0,$inp | |||||
le?vperm $IN1,$IN1,$IN1,$lemask | |||||
subic $len,$len,32 | |||||
vpmsumd $Xl,$IN,$H2l # H^2.lo·Xi.lo | |||||
vpmsumd $Xl1,$IN1,$Hl # H.lo·Xi+1.lo | |||||
subfe r0,r0,r0 # borrow?-1:0 | |||||
vpmsumd $Xm,$IN,$H2 # H^2.hi·Xi.lo+H^2.lo·Xi.hi | |||||
vpmsumd $Xm1,$IN1,$H # H.hi·Xi+1.lo+H.lo·Xi+1.hi | |||||
and r0,r0,$len | |||||
vpmsumd $Xh,$IN,$H2h # H^2.hi·Xi.hi | |||||
vpmsumd $Xh1,$IN1,$Hh # H.hi·Xi+1.hi | |||||
add $inp,$inp,r0 | |||||
vxor $Xl,$Xl,$Xl1 | |||||
vxor $Xm,$Xm,$Xm1 | |||||
vpmsumd $t2,$Xl,$xC2 # 1st reduction phase | |||||
vsldoi $t0,$Xm,$zero,8 | |||||
vsldoi $t1,$zero,$Xm,8 | |||||
vxor $Xh,$Xh,$Xh1 | |||||
vxor $Xl,$Xl,$t0 | |||||
vxor $Xh,$Xh,$t1 | |||||
vsldoi $Xl,$Xl,$Xl,8 | |||||
vxor $Xl,$Xl,$t2 | |||||
lvx_u $IN,r8,$inp | |||||
addi $inp,$inp,32 | |||||
vsldoi $t1,$Xl,$Xl,8 # 2nd reduction phase | |||||
vpmsumd $Xl,$Xl,$xC2 | |||||
le?vperm $IN,$IN,$IN,$lemask | |||||
vxor $t1,$t1,$Xh | |||||
vxor $IN,$IN,$t1 | |||||
vxor $IN,$IN,$Xl | |||||
$UCMP r9,$inp | |||||
bgt Loop_2x # done yet? | |||||
cmplwi $len,0 | |||||
bne Leven | |||||
Lshort: | |||||
vpmsumd $Xl,$IN,$Hl # H.lo·Xi.lo | |||||
vpmsumd $Xm,$IN,$H # H.hi·Xi.lo+H.lo·Xi.hi | |||||
vpmsumd $Xh,$IN,$Hh # H.hi·Xi.hi | |||||
vpmsumd $t2,$Xl,$xC2 # 1st reduction phase | |||||
vsldoi $t0,$Xm,$zero,8 | |||||
vsldoi $t1,$zero,$Xm,8 | |||||
vxor $Xl,$Xl,$t0 | |||||
vxor $Xh,$Xh,$t1 | |||||
vsldoi $Xl,$Xl,$Xl,8 | |||||
vxor $Xl,$Xl,$t2 | |||||
vsldoi $t1,$Xl,$Xl,8 # 2nd reduction phase | |||||
vpmsumd $Xl,$Xl,$xC2 | |||||
vxor $t1,$t1,$Xh | |||||
Leven: | |||||
vxor $Xl,$Xl,$t1 | |||||
le?vperm $Xl,$Xl,$Xl,$lemask | |||||
stvx_u $Xl,0,$Xip # write out Xi | |||||
mtspr 256,$vrsave | |||||
blr | |||||
.long 0 | |||||
.byte 0,12,0x14,0,0,0,4,0 | |||||
.long 0 | |||||
___ | |||||
{ | |||||
my ($Xl3,$Xm2,$IN2,$H3l,$H3,$H3h, | |||||
$Xh3,$Xm3,$IN3,$H4l,$H4,$H4h) = map("v$_",(20..31)); | |||||
my $IN0=$IN; | |||||
my ($H21l,$H21h,$loperm,$hiperm) = ($Hl,$Hh,$H2l,$H2h); | |||||
$code.=<<___; | |||||
.align 5 | |||||
.gcm_ghash_p8_4x: | |||||
Lgcm_ghash_p8_4x: | |||||
$STU $sp,-$FRAME($sp) | |||||
li r10,`15+6*$SIZE_T` | |||||
li r11,`31+6*$SIZE_T` | |||||
stvx v20,r10,$sp | |||||
addi r10,r10,32 | |||||
stvx v21,r11,$sp | |||||
addi r11,r11,32 | |||||
stvx v22,r10,$sp | |||||
addi r10,r10,32 | |||||
stvx v23,r11,$sp | |||||
addi r11,r11,32 | |||||
stvx v24,r10,$sp | |||||
addi r10,r10,32 | |||||
stvx v25,r11,$sp | |||||
addi r11,r11,32 | |||||
stvx v26,r10,$sp | |||||
addi r10,r10,32 | |||||
stvx v27,r11,$sp | |||||
addi r11,r11,32 | |||||
stvx v28,r10,$sp | |||||
addi r10,r10,32 | |||||
stvx v29,r11,$sp | |||||
addi r11,r11,32 | |||||
stvx v30,r10,$sp | |||||
li r10,0x60 | |||||
stvx v31,r11,$sp | |||||
li r0,-1 | |||||
stw $vrsave,`$FRAME-4`($sp) # save vrsave | |||||
mtspr 256,r0 # preserve all AltiVec registers | |||||
lvsl $t0,0,r8 # 0x0001..0e0f | |||||
#lvx_u $H2l,r8,$Htbl # load H^2 | |||||
li r8,0x70 | |||||
lvx_u $H2, r9,$Htbl | |||||
li r9,0x80 | |||||
vspltisb $t1,8 # 0x0808..0808 | |||||
#lvx_u $H2h,r10,$Htbl | |||||
li r10,0x90 | |||||
lvx_u $H3l,r8,$Htbl # load H^3 | |||||
li r8,0xa0 | |||||
lvx_u $H3, r9,$Htbl | |||||
li r9,0xb0 | |||||
lvx_u $H3h,r10,$Htbl | |||||
li r10,0xc0 | |||||
lvx_u $H4l,r8,$Htbl # load H^4 | |||||
li r8,0x10 | |||||
lvx_u $H4, r9,$Htbl | |||||
li r9,0x20 | |||||
lvx_u $H4h,r10,$Htbl | |||||
li r10,0x30 | |||||
vsldoi $t2,$zero,$t1,8 # 0x0000..0808 | |||||
vaddubm $hiperm,$t0,$t2 # 0x0001..1617 | |||||
vaddubm $loperm,$t1,$hiperm # 0x0809..1e1f | |||||
$SHRI $len,$len,4 # this allows to use sign bit | |||||
# as carry | |||||
lvx_u $IN0,0,$inp # load input | |||||
lvx_u $IN1,r8,$inp | |||||
subic. $len,$len,8 | |||||
lvx_u $IN2,r9,$inp | |||||
lvx_u $IN3,r10,$inp | |||||
addi $inp,$inp,0x40 | |||||
le?vperm $IN0,$IN0,$IN0,$lemask | |||||
le?vperm $IN1,$IN1,$IN1,$lemask | |||||
le?vperm $IN2,$IN2,$IN2,$lemask | |||||
le?vperm $IN3,$IN3,$IN3,$lemask | |||||
vxor $Xh,$IN0,$Xl | |||||
vpmsumd $Xl1,$IN1,$H3l | |||||
vpmsumd $Xm1,$IN1,$H3 | |||||
vpmsumd $Xh1,$IN1,$H3h | |||||
vperm $H21l,$H2,$H,$hiperm | |||||
vperm $t0,$IN2,$IN3,$loperm | |||||
vperm $H21h,$H2,$H,$loperm | |||||
vperm $t1,$IN2,$IN3,$hiperm | |||||
vpmsumd $Xm2,$IN2,$H2 # H^2.lo·Xi+2.hi+H^2.hi·Xi+2.lo | |||||
vpmsumd $Xl3,$t0,$H21l # H^2.lo·Xi+2.lo+H.lo·Xi+3.lo | |||||
vpmsumd $Xm3,$IN3,$H # H.hi·Xi+3.lo +H.lo·Xi+3.hi | |||||
vpmsumd $Xh3,$t1,$H21h # H^2.hi·Xi+2.hi+H.hi·Xi+3.hi | |||||
vxor $Xm2,$Xm2,$Xm1 | |||||
vxor $Xl3,$Xl3,$Xl1 | |||||
vxor $Xm3,$Xm3,$Xm2 | |||||
vxor $Xh3,$Xh3,$Xh1 | |||||
blt Ltail_4x | |||||
Loop_4x: | |||||
lvx_u $IN0,0,$inp | |||||
lvx_u $IN1,r8,$inp | |||||
subic. $len,$len,4 | |||||
lvx_u $IN2,r9,$inp | |||||
lvx_u $IN3,r10,$inp | |||||
addi $inp,$inp,0x40 | |||||
le?vperm $IN1,$IN1,$IN1,$lemask | |||||
le?vperm $IN2,$IN2,$IN2,$lemask | |||||
le?vperm $IN3,$IN3,$IN3,$lemask | |||||
le?vperm $IN0,$IN0,$IN0,$lemask | |||||
vpmsumd $Xl,$Xh,$H4l # H^4.lo·Xi.lo | |||||
vpmsumd $Xm,$Xh,$H4 # H^4.hi·Xi.lo+H^4.lo·Xi.hi | |||||
vpmsumd $Xh,$Xh,$H4h # H^4.hi·Xi.hi | |||||
vpmsumd $Xl1,$IN1,$H3l | |||||
vpmsumd $Xm1,$IN1,$H3 | |||||
vpmsumd $Xh1,$IN1,$H3h | |||||
vxor $Xl,$Xl,$Xl3 | |||||
vxor $Xm,$Xm,$Xm3 | |||||
vxor $Xh,$Xh,$Xh3 | |||||
vperm $t0,$IN2,$IN3,$loperm | |||||
vperm $t1,$IN2,$IN3,$hiperm | |||||
vpmsumd $t2,$Xl,$xC2 # 1st reduction phase | |||||
vpmsumd $Xl3,$t0,$H21l # H.lo·Xi+3.lo +H^2.lo·Xi+2.lo | |||||
vpmsumd $Xh3,$t1,$H21h # H.hi·Xi+3.hi +H^2.hi·Xi+2.hi | |||||
vsldoi $t0,$Xm,$zero,8 | |||||
vsldoi $t1,$zero,$Xm,8 | |||||
vxor $Xl,$Xl,$t0 | |||||
vxor $Xh,$Xh,$t1 | |||||
vsldoi $Xl,$Xl,$Xl,8 | |||||
vxor $Xl,$Xl,$t2 | |||||
vsldoi $t1,$Xl,$Xl,8 # 2nd reduction phase | |||||
vpmsumd $Xm2,$IN2,$H2 # H^2.hi·Xi+2.lo+H^2.lo·Xi+2.hi | |||||
vpmsumd $Xm3,$IN3,$H # H.hi·Xi+3.lo +H.lo·Xi+3.hi | |||||
vpmsumd $Xl,$Xl,$xC2 | |||||
vxor $Xl3,$Xl3,$Xl1 | |||||
vxor $Xh3,$Xh3,$Xh1 | |||||
vxor $Xh,$Xh,$IN0 | |||||
vxor $Xm2,$Xm2,$Xm1 | |||||
vxor $Xh,$Xh,$t1 | |||||
vxor $Xm3,$Xm3,$Xm2 | |||||
vxor $Xh,$Xh,$Xl | |||||
bge Loop_4x | |||||
Ltail_4x: | |||||
vpmsumd $Xl,$Xh,$H4l # H^4.lo·Xi.lo | |||||
vpmsumd $Xm,$Xh,$H4 # H^4.hi·Xi.lo+H^4.lo·Xi.hi | |||||
vpmsumd $Xh,$Xh,$H4h # H^4.hi·Xi.hi | |||||
vxor $Xl,$Xl,$Xl3 | |||||
vxor $Xm,$Xm,$Xm3 | |||||
vpmsumd $t2,$Xl,$xC2 # 1st reduction phase | |||||
vsldoi $t0,$Xm,$zero,8 | |||||
vsldoi $t1,$zero,$Xm,8 | |||||
vxor $Xh,$Xh,$Xh3 | |||||
vxor $Xl,$Xl,$t0 | |||||
vxor $Xh,$Xh,$t1 | |||||
vsldoi $Xl,$Xl,$Xl,8 | |||||
vxor $Xl,$Xl,$t2 | |||||
vsldoi $t1,$Xl,$Xl,8 # 2nd reduction phase | |||||
vpmsumd $Xl,$Xl,$xC2 | |||||
vxor $t1,$t1,$Xh | |||||
vxor $Xl,$Xl,$t1 | |||||
addic. $len,$len,4 | |||||
beq Ldone_4x | |||||
lvx_u $IN0,0,$inp | |||||
${UCMP}i $len,2 | |||||
li $len,-4 | |||||
blt Lone | |||||
lvx_u $IN1,r8,$inp | |||||
beq Ltwo | |||||
Lthree: | |||||
lvx_u $IN2,r9,$inp | |||||
le?vperm $IN0,$IN0,$IN0,$lemask | |||||
le?vperm $IN1,$IN1,$IN1,$lemask | |||||
le?vperm $IN2,$IN2,$IN2,$lemask | |||||
vxor $Xh,$IN0,$Xl | |||||
vmr $H4l,$H3l | |||||
vmr $H4, $H3 | |||||
vmr $H4h,$H3h | |||||
vperm $t0,$IN1,$IN2,$loperm | |||||
vperm $t1,$IN1,$IN2,$hiperm | |||||
vpmsumd $Xm2,$IN1,$H2 # H^2.lo·Xi+1.hi+H^2.hi·Xi+1.lo | |||||
vpmsumd $Xm3,$IN2,$H # H.hi·Xi+2.lo +H.lo·Xi+2.hi | |||||
vpmsumd $Xl3,$t0,$H21l # H^2.lo·Xi+1.lo+H.lo·Xi+2.lo | |||||
vpmsumd $Xh3,$t1,$H21h # H^2.hi·Xi+1.hi+H.hi·Xi+2.hi | |||||
vxor $Xm3,$Xm3,$Xm2 | |||||
b Ltail_4x | |||||
.align 4 | |||||
Ltwo: | |||||
le?vperm $IN0,$IN0,$IN0,$lemask | |||||
le?vperm $IN1,$IN1,$IN1,$lemask | |||||
vxor $Xh,$IN0,$Xl | |||||
vperm $t0,$zero,$IN1,$loperm | |||||
vperm $t1,$zero,$IN1,$hiperm | |||||
vsldoi $H4l,$zero,$H2,8 | |||||
vmr $H4, $H2 | |||||
vsldoi $H4h,$H2,$zero,8 | |||||
vpmsumd $Xl3,$t0, $H21l # H.lo·Xi+1.lo | |||||
vpmsumd $Xm3,$IN1,$H # H.hi·Xi+1.lo+H.lo·Xi+2.hi | |||||
vpmsumd $Xh3,$t1, $H21h # H.hi·Xi+1.hi | |||||
b Ltail_4x | |||||
.align 4 | |||||
Lone: | |||||
le?vperm $IN0,$IN0,$IN0,$lemask | |||||
vsldoi $H4l,$zero,$H,8 | |||||
vmr $H4, $H | |||||
vsldoi $H4h,$H,$zero,8 | |||||
vxor $Xh,$IN0,$Xl | |||||
vxor $Xl3,$Xl3,$Xl3 | |||||
vxor $Xm3,$Xm3,$Xm3 | |||||
vxor $Xh3,$Xh3,$Xh3 | |||||
b Ltail_4x | |||||
Ldone_4x: | |||||
le?vperm $Xl,$Xl,$Xl,$lemask | |||||
stvx_u $Xl,0,$Xip # write out Xi | |||||
li r10,`15+6*$SIZE_T` | |||||
li r11,`31+6*$SIZE_T` | |||||
mtspr 256,$vrsave | |||||
lvx v20,r10,$sp | |||||
addi r10,r10,32 | |||||
lvx v21,r11,$sp | |||||
addi r11,r11,32 | |||||
lvx v22,r10,$sp | |||||
addi r10,r10,32 | |||||
lvx v23,r11,$sp | |||||
addi r11,r11,32 | |||||
lvx v24,r10,$sp | |||||
addi r10,r10,32 | |||||
lvx v25,r11,$sp | |||||
addi r11,r11,32 | |||||
lvx v26,r10,$sp | |||||
addi r10,r10,32 | |||||
lvx v27,r11,$sp | |||||
addi r11,r11,32 | |||||
lvx v28,r10,$sp | |||||
addi r10,r10,32 | |||||
lvx v29,r11,$sp | |||||
addi r11,r11,32 | |||||
lvx v30,r10,$sp | |||||
lvx v31,r11,$sp | |||||
addi $sp,$sp,$FRAME | |||||
blr | |||||
.long 0 | |||||
.byte 0,12,0x04,0,0x80,0,4,0 | |||||
.long 0 | |||||
___ | |||||
} | |||||
$code.=<<___; | |||||
.size .gcm_ghash_p8,.-.gcm_ghash_p8 | |||||
.asciz "GHASH for PowerISA 2.07, CRYPTOGAMS by <appro\@openssl.org>" | |||||
.align 2 | |||||
___ | |||||
foreach (split("\n",$code)) { | |||||
s/\`([^\`]*)\`/eval $1/geo; | |||||
if ($flavour =~ /le$/o) { # little-endian | |||||
s/le\?//o or | |||||
s/be\?/#be#/o; | |||||
} else { | |||||
s/le\?/#le#/o or | |||||
s/be\?//o; | |||||
} | |||||
print $_,"\n"; | |||||
} | |||||
close STDOUT; # enforce flush |
@@ -60,7 +60,8 @@ | |||||
#if !defined(OPENSSL_NO_ASM) && \ | #if !defined(OPENSSL_NO_ASM) && \ | ||||
(defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || \ | (defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || \ | ||||
defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)) | |||||
defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64) || \ | |||||
defined(OPENSSL_PPC64LE)) | |||||
#define GHASH_ASM | #define GHASH_ASM | ||||
#endif | #endif | ||||
@@ -145,7 +146,7 @@ static void gcm_init_4bit(u128 Htable[16], uint64_t H[2]) { | |||||
#endif | #endif | ||||
} | } | ||||
#if !defined(GHASH_ASM) || defined(OPENSSL_AARCH64) | |||||
#if !defined(GHASH_ASM) || defined(OPENSSL_AARCH64) || defined(OPENSSL_PPC64LE) | |||||
static const size_t rem_4bit[16] = { | static const size_t rem_4bit[16] = { | ||||
PACK(0x0000), PACK(0x1C20), PACK(0x3840), PACK(0x2460), | PACK(0x0000), PACK(0x1C20), PACK(0x3840), PACK(0x2460), | ||||
PACK(0x7080), PACK(0x6CA0), PACK(0x48C0), PACK(0x54E0), | PACK(0x7080), PACK(0x6CA0), PACK(0x48C0), PACK(0x54E0), | ||||
@@ -405,6 +406,13 @@ static void gcm_ghash_neon(uint64_t Xi[2], const u128 Htable[16], | |||||
#endif | #endif | ||||
#endif | #endif | ||||
#elif defined(OPENSSL_PPC64LE) | |||||
#define GHASH_ASM_PPC64LE | |||||
#define GCM_FUNCREF_4BIT | |||||
void gcm_init_p8(u128 Htable[16], const uint64_t Xi[2]); | |||||
void gcm_gmult_p8(uint64_t Xi[2], const u128 Htable[16]); | |||||
void gcm_ghash_p8(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, | |||||
size_t len); | |||||
#endif | #endif | ||||
#endif | #endif | ||||
@@ -484,6 +492,16 @@ void CRYPTO_gcm128_init(GCM128_CONTEXT *ctx, const void *key, | |||||
ctx->gmult = gcm_gmult_4bit; | ctx->gmult = gcm_gmult_4bit; | ||||
ctx->ghash = gcm_ghash_4bit; | ctx->ghash = gcm_ghash_4bit; | ||||
} | } | ||||
#elif defined(GHASH_ASM_PPC64LE) | |||||
if (CRYPTO_is_PPC64LE_vcrypto_capable()) { | |||||
gcm_init_p8(ctx->Htable, ctx->H.u); | |||||
ctx->gmult = gcm_gmult_p8; | |||||
ctx->ghash = gcm_ghash_p8; | |||||
} else { | |||||
gcm_init_4bit(ctx->Htable, ctx->H.u); | |||||
ctx->gmult = gcm_gmult_4bit; | |||||
ctx->ghash = gcm_ghash_4bit; | |||||
} | |||||
#else | #else | ||||
gcm_init_4bit(ctx->Htable, ctx->H.u); | gcm_init_4bit(ctx->Htable, ctx->H.u); | ||||
ctx->gmult = gcm_gmult_4bit; | ctx->gmult = gcm_gmult_4bit; | ||||
@@ -0,0 +1,299 @@ | |||||
#! /usr/bin/env perl | |||||
# Copyright 2006-2016 The OpenSSL Project Authors. All Rights Reserved. | |||||
# | |||||
# Licensed under the OpenSSL license (the "License"). You may not use | |||||
# this file except in compliance with the License. You can obtain a copy | |||||
# in the file LICENSE in the source distribution or at | |||||
# https://www.openssl.org/source/license.html | |||||
my $flavour = shift; | |||||
my $output = shift; | |||||
open STDOUT,">$output" || die "can't open $output: $!"; | |||||
my %GLOBALS; | |||||
my %TYPES; | |||||
my $dotinlocallabels=($flavour=~/linux/)?1:0; | |||||
################################################################ | |||||
# directives which need special treatment on different platforms | |||||
################################################################ | |||||
my $type = sub { | |||||
my ($dir,$name,$type) = @_; | |||||
$TYPES{$name} = $type; | |||||
if ($flavour =~ /linux/) { | |||||
$name =~ s|^\.||; | |||||
".type $name,$type"; | |||||
} else { | |||||
""; | |||||
} | |||||
}; | |||||
my $globl = sub { | |||||
my $junk = shift; | |||||
my $name = shift; | |||||
my $global = \$GLOBALS{$name}; | |||||
my $type = \$TYPES{$name}; | |||||
my $ret; | |||||
$name =~ s|^\.||; | |||||
SWITCH: for ($flavour) { | |||||
/aix/ && do { if (!$$type) { | |||||
$$type = "\@function"; | |||||
} | |||||
if ($$type =~ /function/) { | |||||
$name = ".$name"; | |||||
} | |||||
last; | |||||
}; | |||||
/osx/ && do { $name = "_$name"; | |||||
last; | |||||
}; | |||||
/linux.*(32|64le)/ | |||||
&& do { $ret .= ".globl $name"; | |||||
if (!$$type) { | |||||
$ret .= "\n.type $name,\@function"; | |||||
$$type = "\@function"; | |||||
} | |||||
last; | |||||
}; | |||||
/linux.*64/ && do { $ret .= ".globl $name"; | |||||
if (!$$type) { | |||||
$ret .= "\n.type $name,\@function"; | |||||
$$type = "\@function"; | |||||
} | |||||
if ($$type =~ /function/) { | |||||
$ret .= "\n.section \".opd\",\"aw\""; | |||||
$ret .= "\n.align 3"; | |||||
$ret .= "\n$name:"; | |||||
$ret .= "\n.quad .$name,.TOC.\@tocbase,0"; | |||||
$ret .= "\n.previous"; | |||||
$name = ".$name"; | |||||
} | |||||
last; | |||||
}; | |||||
} | |||||
$ret = ".globl $name" if (!$ret); | |||||
$$global = $name; | |||||
$ret; | |||||
}; | |||||
my $text = sub { | |||||
my $ret = ($flavour =~ /aix/) ? ".csect\t.text[PR],7" : ".text"; | |||||
$ret = ".abiversion 2\n".$ret if ($flavour =~ /linux.*64le/); | |||||
$ret; | |||||
}; | |||||
my $machine = sub { | |||||
my $junk = shift; | |||||
my $arch = shift; | |||||
if ($flavour =~ /osx/) | |||||
{ $arch =~ s/\"//g; | |||||
$arch = ($flavour=~/64/) ? "ppc970-64" : "ppc970" if ($arch eq "any"); | |||||
} | |||||
".machine $arch"; | |||||
}; | |||||
my $size = sub { | |||||
if ($flavour =~ /linux/) | |||||
{ shift; | |||||
my $name = shift; | |||||
my $real = $GLOBALS{$name} ? \$GLOBALS{$name} : \$name; | |||||
my $ret = ".size $$real,.-$$real"; | |||||
$name =~ s|^\.||; | |||||
if ($$real ne $name) { | |||||
$ret .= "\n.size $name,.-$$real"; | |||||
} | |||||
$ret; | |||||
} | |||||
else | |||||
{ ""; } | |||||
}; | |||||
my $asciz = sub { | |||||
shift; | |||||
my $line = join(",",@_); | |||||
if ($line =~ /^"(.*)"$/) | |||||
{ ".byte " . join(",",unpack("C*",$1),0) . "\n.align 2"; } | |||||
else | |||||
{ ""; } | |||||
}; | |||||
my $quad = sub { | |||||
shift; | |||||
my @ret; | |||||
my ($hi,$lo); | |||||
for (@_) { | |||||
if (/^0x([0-9a-f]*?)([0-9a-f]{1,8})$/io) | |||||
{ $hi=$1?"0x$1":"0"; $lo="0x$2"; } | |||||
elsif (/^([0-9]+)$/o) | |||||
{ $hi=$1>>32; $lo=$1&0xffffffff; } # error-prone with 32-bit perl | |||||
else | |||||
{ $hi=undef; $lo=$_; } | |||||
if (defined($hi)) | |||||
{ push(@ret,$flavour=~/le$/o?".long\t$lo,$hi":".long\t$hi,$lo"); } | |||||
else | |||||
{ push(@ret,".quad $lo"); } | |||||
} | |||||
join("\n",@ret); | |||||
}; | |||||
################################################################ | |||||
# simplified mnemonics not handled by at least one assembler | |||||
################################################################ | |||||
my $cmplw = sub { | |||||
my $f = shift; | |||||
my $cr = 0; $cr = shift if ($#_>1); | |||||
# Some out-of-date 32-bit GNU assembler just can't handle cmplw... | |||||
($flavour =~ /linux.*32/) ? | |||||
" .long ".sprintf "0x%x",31<<26|$cr<<23|$_[0]<<16|$_[1]<<11|64 : | |||||
" cmplw ".join(',',$cr,@_); | |||||
}; | |||||
my $bdnz = sub { | |||||
my $f = shift; | |||||
my $bo = $f=~/[\+\-]/ ? 16+9 : 16; # optional "to be taken" hint | |||||
" bc $bo,0,".shift; | |||||
} if ($flavour!~/linux/); | |||||
my $bltlr = sub { | |||||
my $f = shift; | |||||
my $bo = $f=~/\-/ ? 12+2 : 12; # optional "not to be taken" hint | |||||
($flavour =~ /linux/) ? # GNU as doesn't allow most recent hints | |||||
" .long ".sprintf "0x%x",19<<26|$bo<<21|16<<1 : | |||||
" bclr $bo,0"; | |||||
}; | |||||
my $bnelr = sub { | |||||
my $f = shift; | |||||
my $bo = $f=~/\-/ ? 4+2 : 4; # optional "not to be taken" hint | |||||
($flavour =~ /linux/) ? # GNU as doesn't allow most recent hints | |||||
" .long ".sprintf "0x%x",19<<26|$bo<<21|2<<16|16<<1 : | |||||
" bclr $bo,2"; | |||||
}; | |||||
my $beqlr = sub { | |||||
my $f = shift; | |||||
my $bo = $f=~/-/ ? 12+2 : 12; # optional "not to be taken" hint | |||||
($flavour =~ /linux/) ? # GNU as doesn't allow most recent hints | |||||
" .long ".sprintf "0x%X",19<<26|$bo<<21|2<<16|16<<1 : | |||||
" bclr $bo,2"; | |||||
}; | |||||
# GNU assembler can't handle extrdi rA,rS,16,48, or when sum of last two | |||||
# arguments is 64, with "operand out of range" error. | |||||
my $extrdi = sub { | |||||
my ($f,$ra,$rs,$n,$b) = @_; | |||||
$b = ($b+$n)&63; $n = 64-$n; | |||||
" rldicl $ra,$rs,$b,$n"; | |||||
}; | |||||
my $vmr = sub { | |||||
my ($f,$vx,$vy) = @_; | |||||
" vor $vx,$vy,$vy"; | |||||
}; | |||||
# Some ABIs specify vrsave, special-purpose register #256, as reserved | |||||
# for system use. | |||||
my $no_vrsave = ($flavour =~ /aix|linux64le/); | |||||
my $mtspr = sub { | |||||
my ($f,$idx,$ra) = @_; | |||||
if ($idx == 256 && $no_vrsave) { | |||||
" or $ra,$ra,$ra"; | |||||
} else { | |||||
" mtspr $idx,$ra"; | |||||
} | |||||
}; | |||||
my $mfspr = sub { | |||||
my ($f,$rd,$idx) = @_; | |||||
if ($idx == 256 && $no_vrsave) { | |||||
" li $rd,-1"; | |||||
} else { | |||||
" mfspr $rd,$idx"; | |||||
} | |||||
}; | |||||
# PowerISA 2.06 stuff | |||||
sub vsxmem_op { | |||||
my ($f, $vrt, $ra, $rb, $op) = @_; | |||||
" .long ".sprintf "0x%X",(31<<26)|($vrt<<21)|($ra<<16)|($rb<<11)|($op*2+1); | |||||
} | |||||
# made-up unaligned memory reference AltiVec/VMX instructions | |||||
my $lvx_u = sub { vsxmem_op(@_, 844); }; # lxvd2x | |||||
my $stvx_u = sub { vsxmem_op(@_, 972); }; # stxvd2x | |||||
my $lvdx_u = sub { vsxmem_op(@_, 588); }; # lxsdx | |||||
my $stvdx_u = sub { vsxmem_op(@_, 716); }; # stxsdx | |||||
my $lvx_4w = sub { vsxmem_op(@_, 780); }; # lxvw4x | |||||
my $stvx_4w = sub { vsxmem_op(@_, 908); }; # stxvw4x | |||||
# PowerISA 2.07 stuff | |||||
sub vcrypto_op { | |||||
my ($f, $vrt, $vra, $vrb, $op) = @_; | |||||
" .long ".sprintf "0x%X",(4<<26)|($vrt<<21)|($vra<<16)|($vrb<<11)|$op; | |||||
} | |||||
my $vcipher = sub { vcrypto_op(@_, 1288); }; | |||||
my $vcipherlast = sub { vcrypto_op(@_, 1289); }; | |||||
my $vncipher = sub { vcrypto_op(@_, 1352); }; | |||||
my $vncipherlast= sub { vcrypto_op(@_, 1353); }; | |||||
my $vsbox = sub { vcrypto_op(@_, 0, 1480); }; | |||||
my $vshasigmad = sub { my ($st,$six)=splice(@_,-2); vcrypto_op(@_, $st<<4|$six, 1730); }; | |||||
my $vshasigmaw = sub { my ($st,$six)=splice(@_,-2); vcrypto_op(@_, $st<<4|$six, 1666); }; | |||||
my $vpmsumb = sub { vcrypto_op(@_, 1032); }; | |||||
my $vpmsumd = sub { vcrypto_op(@_, 1224); }; | |||||
my $vpmsubh = sub { vcrypto_op(@_, 1096); }; | |||||
my $vpmsumw = sub { vcrypto_op(@_, 1160); }; | |||||
my $vaddudm = sub { vcrypto_op(@_, 192); }; | |||||
my $mtsle = sub { | |||||
my ($f, $arg) = @_; | |||||
" .long ".sprintf "0x%X",(31<<26)|($arg<<21)|(147*2); | |||||
}; | |||||
# PowerISA 3.0 stuff | |||||
my $maddhdu = sub { | |||||
my ($f, $rt, $ra, $rb, $rc) = @_; | |||||
" .long ".sprintf "0x%X",(4<<26)|($rt<<21)|($ra<<16)|($rb<<11)|($rc<<6)|49; | |||||
}; | |||||
my $maddld = sub { | |||||
my ($f, $rt, $ra, $rb, $rc) = @_; | |||||
" .long ".sprintf "0x%X",(4<<26)|($rt<<21)|($ra<<16)|($rb<<11)|($rc<<6)|51; | |||||
}; | |||||
my $darn = sub { | |||||
my ($f, $rt, $l) = @_; | |||||
" .long ".sprintf "0x%X",(31<<26)|($rt<<21)|($l<<16)|(755<<1); | |||||
}; | |||||
while($line=<>) { | |||||
$line =~ s|[#!;].*$||; # get rid of asm-style comments... | |||||
$line =~ s|/\*.*\*/||; # ... and C-style comments... | |||||
$line =~ s|^\s+||; # ... and skip white spaces in beginning... | |||||
$line =~ s|\s+$||; # ... and at the end | |||||
{ | |||||
$line =~ s|\.L(\w+)|L$1|g; # common denominator for Locallabel | |||||
$line =~ s|\bL(\w+)|\.L$1|g if ($dotinlocallabels); | |||||
} | |||||
{ | |||||
$line =~ s|(^[\.\w]+)\:\s*||; | |||||
my $label = $1; | |||||
if ($label) { | |||||
my $xlated = ($GLOBALS{$label} or $label); | |||||
print "$xlated:"; | |||||
if ($flavour =~ /linux.*64le/) { | |||||
if ($TYPES{$label} =~ /function/) { | |||||
printf "\n.localentry %s,0\n",$xlated; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
{ | |||||
$line =~ s|^\s*(\.?)(\w+)([\.\+\-]?)\s*||; | |||||
my $c = $1; $c = "\t" if ($c eq ""); | |||||
my $mnemonic = $2; | |||||
my $f = $3; | |||||
my $opcode = eval("\$$mnemonic"); | |||||
$line =~ s/\b(c?[rf]|v|vs)([0-9]+)\b/$2/g if ($c ne "." and $flavour !~ /osx/); | |||||
if (ref($opcode) eq 'CODE') { $line = &$opcode($f,split(',',$line)); } | |||||
elsif ($mnemonic) { $line = $c.$mnemonic.$f."\t".$line; } | |||||
} | |||||
print $line if ($line); | |||||
print "\n"; | |||||
} | |||||
close STDOUT; |
@@ -83,8 +83,9 @@ extern "C" { | |||||
#elif defined(__arm) || defined(__arm__) || defined(_M_ARM) | #elif defined(__arm) || defined(__arm__) || defined(_M_ARM) | ||||
#define OPENSSL_32_BIT | #define OPENSSL_32_BIT | ||||
#define OPENSSL_ARM | #define OPENSSL_ARM | ||||
#elif defined(__PPC64__) || defined(__powerpc64__) | |||||
#elif (defined(__PPC64__) || defined(__powerpc64__)) && defined(_LITTLE_ENDIAN) | |||||
#define OPENSSL_64_BIT | #define OPENSSL_64_BIT | ||||
#define OPENSSL_PPC64LE | |||||
#elif defined(__mips__) && !defined(__LP64__) | #elif defined(__mips__) && !defined(__LP64__) | ||||
#define OPENSSL_32_BIT | #define OPENSSL_32_BIT | ||||
#define OPENSSL_MIPS | #define OPENSSL_MIPS | ||||
@@ -165,6 +165,14 @@ static inline int CRYPTO_is_ARMv8_PMULL_capable(void) { | |||||
#endif /* OPENSSL_STATIC_ARMCAP */ | #endif /* OPENSSL_STATIC_ARMCAP */ | ||||
#endif /* OPENSSL_ARM || OPENSSL_AARCH64 */ | #endif /* OPENSSL_ARM || OPENSSL_AARCH64 */ | ||||
#if defined(OPENSSL_PPC64LE) | |||||
/* CRYPTO_is_PPC64LE_vcrypto_capable returns true iff the current CPU supports | |||||
* the Vector.AES category of instructions. */ | |||||
int CRYPTO_is_PPC64LE_vcrypto_capable(void); | |||||
#endif /* OPENSSL_PPC64LE */ | |||||
#if defined(__cplusplus) | #if defined(__cplusplus) | ||||
} /* extern C */ | } /* extern C */ | ||||