#! /usr/bin/env perl
# Copyright 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/.
# ====================================================================
# March 2016
#
# Initial support for Fujitsu SPARC64 X/X+ comprises minimally
# required key setup and single-block procedures.
#
# April 2016
#
# Add "teaser" CBC and CTR mode-specific subroutines. "Teaser" means
# that parallelizeable nature of CBC decrypt and CTR is not utilized
# yet. CBC encrypt on the other hand is as good as it can possibly
# get processing one byte in 4.1 cycles with 128-bit key on SPARC64 X.
# This is ~6x faster than pure software implementation...
#
# July 2016
#
# Switch from faligndata to fshiftorx, which allows to omit alignaddr
# instructions and improve single-block and short-input performance
# with misaligned data.
$output = pop;
open STDOUT,">$output";
{
my ($inp,$out,$key,$rounds,$tmp,$mask) = map("%o$_",(0..5));
$code.=<<___;
#include "sparc_arch.h"
#define LOCALS (STACK_BIAS+STACK_FRAME)
.text
.globl aes_fx_encrypt
.align 32
aes_fx_encrypt:
and $inp, 7, $tmp ! is input aligned?
andn $inp, 7, $inp
ldd [$key + 0], %f6 ! round[0]
ldd [$key + 8], %f8
mov %o7, %g1
ld [$key + 240], $rounds
1: call .+8
add %o7, .Linp_align-1b, %o7
sll $tmp, 3, $tmp
ldd [$inp + 0], %f0 ! load input
brz,pt $tmp, .Lenc_inp_aligned
ldd [$inp + 8], %f2
ldd [%o7 + $tmp], %f14 ! shift left params
ldd [$inp + 16], %f4
fshiftorx %f0, %f2, %f14, %f0
fshiftorx %f2, %f4, %f14, %f2
.Lenc_inp_aligned:
ldd [$key + 16], %f10 ! round[1]
ldd [$key + 24], %f12
fxor %f0, %f6, %f0 ! ^=round[0]
fxor %f2, %f8, %f2
ldd [$key + 32], %f6 ! round[2]
ldd [$key + 40], %f8
add $key, 32, $key
sub $rounds, 4, $rounds
.Loop_enc:
fmovd %f0, %f4
faesencx %f2, %f10, %f0
faesencx %f4, %f12, %f2
ldd [$key + 16], %f10
ldd [$key + 24], %f12
add $key, 32, $key
fmovd %f0, %f4
faesencx %f2, %f6, %f0
faesencx %f4, %f8, %f2
ldd [$key + 0], %f6
ldd [$key + 8], %f8
brnz,a $rounds, .Loop_enc
sub $rounds, 2, $rounds
andcc $out, 7, $tmp ! is output aligned?
andn $out, 7, $out
mov 0xff, $mask
srl $mask, $tmp, $mask
add %o7, 64, %o7
sll $tmp, 3, $tmp
fmovd %f0, %f4
faesencx %f2, %f10, %f0
faesencx %f4, %f12, %f2
ldd [%o7 + $tmp], %f14 ! shift right params
fmovd %f0, %f4
faesenclx %f2, %f6, %f0
faesenclx %f4, %f8, %f2
bnz,pn %icc, .Lenc_out_unaligned
mov %g1, %o7
std %f0, [$out + 0]
retl
std %f2, [$out + 8]
.align 16
.Lenc_out_unaligned:
add $out, 16, $inp
orn %g0, $mask, $tmp
fshiftorx %f0, %f0, %f14, %f4
fshiftorx %f0, %f2, %f14, %f6
fshiftorx %f2, %f2, %f14, %f8
stda %f4, [$out + $mask]0xc0 ! partial store
std %f6, [$out + 8]
stda %f8, [$inp + $tmp]0xc0 ! partial store
retl
nop
.type aes_fx_encrypt,#function
.size aes_fx_encrypt,.-aes_fx_encrypt
.globl aes_fx_decrypt
.align 32
aes_fx_decrypt:
and $inp, 7, $tmp ! is input aligned?
andn $inp, 7, $inp
ldd [$key + 0], %f6 ! round[0]
ldd [$key + 8], %f8
mov %o7, %g1
ld [$key + 240], $rounds
1: call .+8
add %o7, .Linp_align-1b, %o7
sll $tmp, 3, $tmp
ldd [$inp + 0], %f0 ! load input
brz,pt $tmp, .Ldec_inp_aligned
ldd [$inp + 8], %f2
ldd [%o7 + $tmp], %f14 ! shift left params
ldd [$inp + 16], %f4
fshiftorx %f0, %f2, %f14, %f0
fshiftorx %f2, %f4, %f14, %f2
.Ldec_inp_aligned:
ldd [$key + 16], %f10 ! round[1]
ldd [$key + 24], %f12
fxor %f0, %f6, %f0 ! ^=round[0]
fxor %f2, %f8, %f2
ldd [$key + 32], %f6 ! round[2]
ldd [$key + 40], %f8
add $key, 32, $key
sub $rounds, 4, $rounds
.Loop_dec:
fmovd %f0, %f4
faesdecx %f2, %f10, %f0
faesdecx %f4, %f12, %f2
ldd [$key + 16], %f10
ldd [$key + 24], %f12
add $key, 32, $key
fmovd %f0, %f4
faesdecx %f2, %f6, %f0
faesdecx %f4, %f8, %f2
ldd [$key + 0], %f6
ldd [$key + 8], %f8
brnz,a $rounds, .Loop_dec
sub $rounds, 2, $rounds
andcc $out, 7, $tmp ! is output aligned?
andn $out, 7, $out
mov 0xff, $mask
srl $mask, $tmp, $mask
add %o7, 64, %o7
sll $tmp, 3, $tmp
fmovd %f0, %f4
faesdecx %f2, %f10, %f0
faesdecx %f4, %f12, %f2
ldd [%o7 + $tmp], %f14 ! shift right params
fmovd %f0, %f4
faesdeclx %f2, %f6, %f0
faesdeclx %f4, %f8, %f2
bnz,pn %icc, .Ldec_out_unaligned
mov %g1, %o7
std %f0, [$out + 0]
retl
std %f2, [$out + 8]
.align 16
.Ldec_out_unaligned:
add $out, 16, $inp
orn %g0, $mask, $tmp
fshiftorx %f0, %f0, %f14, %f4
fshiftorx %f0, %f2, %f14, %f6
fshiftorx %f2, %f2, %f14, %f8
stda %f4, [$out + $mask]0xc0 ! partial store
std %f6, [$out + 8]
stda %f8, [$inp + $tmp]0xc0 ! partial store
retl
nop
.type aes_fx_decrypt,#function
.size aes_fx_decrypt,.-aes_fx_decrypt
___
}
{
my ($inp,$bits,<