#!/usr/bin/env perl
#***************************************************************************
#                                  _   _ ____  _
#  Project                     ___| | | |  _ \| |
#                             / __| | | | |_) | |
#                            | (__| |_| |  _ <| |___
#                             \___|\___/|_| \_\_____|
#
# Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at https://curl.se/docs/copyright.html.
#
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
# copies of the Software, and permit persons to whom the Software is
# furnished to do so, under the terms of the COPYING file.
#
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
###########################################################################
# Determine if the given curl executable supports the 'openssl' SSL engine
if ( $#ARGV != 0 )
{
    print "Usage: $0 curl-executable\n";
    exit 3;
}
if (!open(CURL, "@ARGV[0] -s --engine list|"))
{
    print "Can't get SSL engine list\n";
    exit 2;
}
while( <CURL> )
{
    exit 0 if ( /openssl/ );
}
close CURL;
print "openssl engine not supported\n";
exit 1;


#!/usr/bin/env perl
#***************************************************************************
#                                  _   _ ____  _
#  Project                     ___| | | |  _ \| |
#                             / __| | | | |_) | |
#                            | (__| |_| |  _ <| |___
#                             \___|\___/|_| \_\_____|
#
# Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at https://curl.se/docs/copyright.html.
#
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
# copies of the Software, and permit persons to whom the Software is
# furnished to do so, under the terms of the COPYING file.
#
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
###########################################################################
# Perform simple file and directory manipulation in a portable way
if ( $#ARGV <= 0 )
{
    print "Usage: $0 mkdir|rmdir|rm|move|gone path1 [path2] [more commands...]\n";
    exit 1;
}

use File::Copy;
while(@ARGV) {
    my $cmd = shift @ARGV;
    my $arg = shift @ARGV;
    if ($cmd eq "mkdir") {
        mkdir $arg || die "$!";
    }
    elsif ($cmd eq "rmdir") {
        rmdir $arg || die "$!";
    }
    elsif ($cmd eq "rm") {
        unlink $arg || die "$!";
    }
    elsif ($cmd eq "move") {
        my $arg2 = shift @ARGV;
        move($arg,$arg2) || die "$!";
    }
    elsif ($cmd eq "gone") {
        ! -e $arg || die "Path $arg exists";
    } else {
        print "Unsupported command $cmd\n";
        exit 1;
    }
}
exit 0;


#!/usr/bin/env perl
#***************************************************************************
#                                  _   _ ____  _
#  Project                     ___| | | |  _ \| |
#                             / __| | | | |_) | |
#                            | (__| |_| |  _ <| |___
#                             \___|\___/|_| \_\_____|
#
# Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at https://curl.se/docs/copyright.html.
#
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
# copies of the Software, and permit persons to whom the Software is
# furnished to do so, under the terms of the COPYING file.
#
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
###########################################################################
# Prepare a directory with known files and clean up afterwards
use Time::Local;

if ( $#ARGV < 1 )
{
    print "Usage: $0 prepare|postprocess dir [logfile]\n";
    exit 1;
}

# <precheck> expects an error message on stdout
sub errout {
    print $_[0] . "\n";
    exit 1;
}

if ($ARGV[0] eq "prepare")
{
    my $dirname = $ARGV[1];
    mkdir $dirname || errout "$!";
    chdir $dirname;

    # Create the files in alphabetical order, to increase the chances
    # of receiving a consistent set of directory contents regardless
    # of whether the server alphabetizes the results or not.
    mkdir "asubdir" || errout "$!";
    chmod 0777, "asubdir";

    open(FILE, ">plainfile.txt") || errout "$!";
    binmode FILE;
    print FILE "Test file to support curl test suite\n";
    close(FILE);
    # The mtime is specifically chosen to be an even number so that it can be
    # represented exactly on a FAT filesystem.
    utime time, timegm(0,0,12,1,0,100), "plainfile.txt";
    chmod 0666, "plainfile.txt";

    open(FILE, ">rofile.txt") || errout "$!";
    binmode FILE;
    print FILE "Read-only test file to support curl test suite\n";
    close(FILE);
    # The mtime is specifically chosen to be an even number so that it can be
    # represented exactly on a FAT filesystem.
    utime time, timegm(0,0,12,31,11,100), "rofile.txt";
    chmod 0444, "rofile.txt";

    exit 0;
}
elsif ($ARGV[0] eq "postprocess")
{
    my $dirname = $ARGV[1];
    my $logfile = $ARGV[2];

    # Clean up the test directory
    unlink "$dirname/rofile.txt";
    unlink "$dirname/plainfile.txt";
    rmdir "$dirname/asubdir";

    rmdir $dirname || die "$!";

    if ($logfile) {
        # Process the directory file to remove all information that
        # could be inconsistent from one test run to the next (e.g.
        # file date) or may be unsupported on some platforms (e.g.
        # Windows). Also, since 7.17.0, the sftp directory listing
        # format can be dependent on the server (with a recent
        # enough version of libssh2) so this script must also
        # canonicalize the format.  Here are examples of the general
        # format supported:
        # -r--r--r--   12 ausername grp            47 Dec 31  2000 rofile.txt
        # -r--r--r--   1  1234  4321         47 Dec 31  2000 rofile.txt
        # The "canonical" format is similar to the first (which is
        # the one generated on a typical Linux installation):
        # -r-?r-?r-?   12 U         U              47 Dec 31  2000 rofile.txt

        my @canondir;
        open(IN, "<$logfile") || die "$!";
        while (<IN>) {
            /^(.)(..).(..).(..).\s*(\S+)\s+\S+\s+\S+\s+(\S+)\s+(\S+\s+\S+\s+\S+)\s+(.*)$/;
            if ($1 eq "d") {
                # Skip current and parent directory listing, because some SSH
                # servers (eg. OpenSSH for Windows) are not listing those
                if ($8 eq "." || $8 eq "..") {
                    next;
                }
                # Erase all directory metadata except for the name, as it is not
                # consistent for across all test systems and filesystems
                push @canondir, "d?????????    N U         U               N ???  N NN:NN $8\n";
            } elsif ($1 eq "-") {
                # Replace missing group and other permissions with user
                # permissions (eg. on Windows) due to them being shown as *
                my ($u, $g, $o) = ($2, $3, $4);
                if($g eq "**") {
                    $g = $u;
                }
                if($o eq "**") {
                    $o = $u;
                }
                # Erase user and group names, as they are not consistent across
                # all test systems
                my $line = sprintf("%s%s?%s?%s?%5d U         U %15d %s %s\n", $1,$u,$g,$o,$5,$6,$7,$8);
                push @canondir, $line;
            } else {
                # Unexpected format; just pass it through and let the test fail
                push @canondir, $_;
            }
        }
        close(IN);

        @canondir = sort {substr($a,57) cmp substr($b,57)} @canondir;
        my $newfile = $logfile . ".new";
        open(OUT, ">$newfile") || die "$!";
        print OUT join('', @canondir);
        close(OUT);

        unlink $logfile;
        rename $newfile, $logfile;
    }

    exit 0;
}
print "Unsupported command $ARGV[0]\n";
exit 1;


#!/usr/bin/env perl
#***************************************************************************
#                                  _   _ ____  _
#  Project                     ___| | | |  _ \| |
#                             / __| | | | |_) | |
#                            | (__| |_| |  _ <| |___
#                             \___|\___/|_| \_\_____|
#
# Copyright (C) 2004 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at https://curl.se/docs/copyright.html.
#
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
# copies of the Software, and permit persons to whom the Software is
# furnished to do so, under the terms of the COPYING file.
#
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
###########################################################################

use MIME::Base64 qw(encode_base64);

my $buf;
while(read(STDIN, $buf, 60*57)) {
    my $enc = encode_base64($buf);
    print "$enc";
}


#!/usr/bin/perl

$size = shift;

if ($size eq "")
{
    die "usage:  dbgen.pl [size]\n";
}

@firstnames = ("Al", "Bob", "Charles", "David", "Egon", "Farbood",
               "George", "Hank", "Inki", "James");
@lastnames = ("Aranow", "Barker", "Corsetti", "Dershowitz", "Engleman",
              "Franklin", "Grice", "Haverford", "Ilvedson", "Jones");
@states = ("AL", "AK", "AZ", "AR", "CA", "CO", "CT", "DE", "FL", "GA",
           "HI", "ID", "IL", "IN", "IA", "KS", "KY", "LA", "ME", "MD",
           "MA", "MI", "MN", "MS", "MO", "MT", "NE", "NV", "NH", "NJ",
           "NM", "NY", "NC", "ND", "OH", "OK", "OR", "PA", "RI", "SC",
           "SD", "TN", "TX", "UT", "VT", "VA", "WA", "WV", "WI", "WY");

print "<?xml version=\"1.0\"?>\n";
print "\n";
print "<table>\n";

for ($i=0; $i<$size; $i++)
{
    $first = $firstnames [$i % 10];
    $last = $lastnames [($i / 10) % 10];
    $state = $states [($i / 100) % 50];
    $zip = 22000 + $i / 5000;

    printf "  <row>\n";
    printf "    <id>%04d</id>\n", $i;
    printf "    <firstname>$first</firstname>\n", $i;
    printf "    <lastname>$last</lastname>\n", $i;
    printf "    <street>%d Any St.</street>\n", ($i % 100) + 1;
    printf "    <city>Anytown</city>\n";
    printf "    <state>$state</state>\n";
    printf "    <zip>%d</zip>\n", $zip;
    printf "  </row>\n";
}

print "</table>\n";


#!/usr/bin/perl

$size = shift;

if ($size eq "")
{
    die "usage:  dbgen.pl [size]\n";
}

@firstnames = ("Al", "Bob", "Charles", "David", "Egon", "Farbood",
               "George", "Hank", "Inki", "James");
@lastnames = ("Aranow", "Barker", "Corsetti", "Dershowitz", "Engleman",
              "Franklin", "Grice", "Haverford", "Ilvedson", "Jones");
@states = ("AL", "AK", "AZ", "AR", "CA", "CO", "CT", "DE", "FL", "GA",
           "HI", "ID", "IL", "IN", "IA", "KS", "KY", "LA", "ME", "MD",
           "MA", "MI", "MN", "MS", "MO", "MT", "NE", "NV", "NH", "NJ",
           "NM", "NY", "NC", "ND", "OH", "OK", "OR", "PA", "RI", "SC",
           "SD", "TN", "TX", "UT", "VT", "VA", "WA", "WV", "WI", "WY");

print "<?xml version=\"1.0\"?>\n";
print "\n";
print "<table>\n";

for ($i=0; $i<$size; $i++)
{
    $first = $firstnames [$i % 10];
    $last = $lastnames [($i / 10) % 10];
    $state = $states [($i / 100) % 50];
    $zip = 22000 + $i / 5000;

    printf "  <row\n";
    printf "    id='%04d'\n", $i;
    printf "    firstname='$first'\n", $i;
    printf "    lastname='$last'\n", $i;
    printf "    street='%d Any St.'\n", ($i % 100) + 1;
    printf "    city='Anytown'\n";
    printf "    state='$state'\n";
    printf "    zip='%d'/>\n", $zip;
}

print "</table>\n";


#! /usr/bin/env perl
# Copyright 1995-2018 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

# Generate progs.h file by looking for command mains in list of C files
# passed on the command line.

use strict;
use warnings;
use lib '.';
use configdata qw/@disablables %unified_info/;

my %commands     = ();
my $cmdre        = qr/^\s*int\s+([a-z_][a-z0-9_]*)_main\(\s*int\s+argc\s*,/;
my $apps_openssl = shift @ARGV;
my $YEAR         = [localtime()]->[5] + 1900;

# because the program apps/openssl has object files as sources, and
# they then have the corresponding C files as source, we need to chain
# the lookups in %unified_info
my @openssl_source =
    map { @{$unified_info{sources}->{$_}} }
    grep { /\.o$/ }
        @{$unified_info{sources}->{$apps_openssl}};

foreach my $filename (@openssl_source) {
    open F, $filename or die "Couldn't open $filename: $!\n";
    foreach ( grep /$cmdre/, <F> ) {
        my @foo = /$cmdre/;
        $commands{$1} = 1;
    }
    close F;
}

@ARGV = sort keys %commands;

print <<"EOF";
/*
 * WARNING: do not edit!
 * Generated by apps/progs.pl
 *
 * Copyright 1995-$YEAR 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
 */

typedef enum FUNC_TYPE {
    FT_none, FT_general, FT_md, FT_cipher, FT_pkey,
    FT_md_alg, FT_cipher_alg
} FUNC_TYPE;

typedef struct function_st {
    FUNC_TYPE type;
    const char *name;
    int (*func)(int argc, char *argv[]);
    const OPTIONS *help;
} FUNCTION;

DEFINE_LHASH_OF(FUNCTION);

EOF

foreach (@ARGV) {
    printf "extern int %s_main(int argc, char *argv[]);\n", $_;
}
print "\n";

foreach (@ARGV) {
    printf "extern const OPTIONS %s_options[];\n", $_;
}
print "\n";

my %cmd_disabler = (
    ciphers  => "sock",
    genrsa   => "rsa",
    rsautl   => "rsa",
    gendsa   => "dsa",
    dsaparam => "dsa",
    gendh    => "dh",
    dhparam  => "dh",
    ecparam  => "ec",
    pkcs12   => "des",
);

print "#ifdef INCLUDE_FUNCTION_TABLE\n";
print "static FUNCTION functions[] = {\n";
foreach my $cmd ( @ARGV ) {
    my $str = "    {FT_general, \"$cmd\", ${cmd}_main, ${cmd}_options},\n";
    if ($cmd =~ /^s_/) {
        print "#ifndef OPENSSL_NO_SOCK\n${str}#endif\n";
    } elsif (grep { $cmd eq $_ } @disablables) {
        print "#ifndef OPENSSL_NO_" . uc($cmd) . "\n${str}#endif\n";
    } elsif (my $disabler = $cmd_disabler{$cmd}) {
        print "#ifndef OPENSSL_NO_" . uc($disabler) . "\n${str}#endif\n";
    } else {
        print $str;
    }
}

my %md_disabler = (
    blake2b512 => "blake2",
    blake2s256 => "blake2",
);
foreach my $cmd (
    "md2", "md4", "md5",
    "gost",
    "sha1", "sha224", "sha256", "sha384",
    "sha512", "sha512-224", "sha512-256",
    "sha3-224", "sha3-256", "sha3-384", "sha3-512",
    "shake128", "shake256",
    "mdc2", "rmd160", "blake2b512", "blake2s256",
    "sm3"
) {
    my $str = "    {FT_md, \"$cmd\", dgst_main},\n";
    if (grep { $cmd eq $_ } @disablables) {
        print "#ifndef OPENSSL_NO_" . uc($cmd) . "\n${str}#endif\n";
    } elsif (my $disabler = $md_disabler{$cmd}) {
        print "#ifndef OPENSSL_NO_" . uc($disabler) . "\n${str}#endif\n";
    } else {
        print $str;
    }
}

my %cipher_disabler = (
    des3  => "des",
    desx  => "des",
    cast5 => "cast",
);
foreach my $cmd (
    "aes-128-cbc", "aes-128-ecb",
    "aes-192-cbc", "aes-192-ecb",
    "aes-256-cbc", "aes-256-ecb",
    "aria-128-cbc", "aria-128-cfb",
    "aria-128-ctr", "aria-128-ecb", "aria-128-ofb",
    "aria-128-cfb1", "aria-128-cfb8",
    "aria-192-cbc", "aria-192-cfb",
    "aria-192-ctr", "aria-192-ecb", "aria-192-ofb",
    "aria-192-cfb1", "aria-192-cfb8",
    "aria-256-cbc", "aria-256-cfb",
    "aria-256-ctr", "aria-256-ecb", "aria-256-ofb",
    "aria-256-cfb1", "aria-256-cfb8",
    "camellia-128-cbc", "camellia-128-ecb",
    "camellia-192-cbc", "camellia-192-ecb",
    "camellia-256-cbc", "camellia-256-ecb",
    "base64", "zlib",
    "des", "des3", "desx", "idea", "seed", "rc4", "rc4-40",
    "rc2", "bf", "cast", "rc5",
    "des-ecb", "des-ede", "des-ede3",
    "des-cbc", "des-ede-cbc","des-ede3-cbc",
    "des-cfb", "des-ede-cfb","des-ede3-cfb",
    "des-ofb", "des-ede-ofb","des-ede3-ofb",
    "idea-cbc","idea-ecb", "idea-cfb", "idea-ofb",
    "seed-cbc","seed-ecb", "seed-cfb", "seed-ofb",
    "rc2-cbc", "rc2-ecb", "rc2-cfb","rc2-ofb", "rc2-64-cbc", "rc2-40-cbc",
    "bf-cbc", "bf-ecb", "bf-cfb", "bf-ofb",
    "cast5-cbc","cast5-ecb", "cast5-cfb","cast5-ofb",
    "cast-cbc", "rc5-cbc", "rc5-ecb", "rc5-cfb", "rc5-ofb",
    "sm4-cbc", "sm4-ecb", "sm4-cfb", "sm4-ofb", "sm4-ctr"
) {
    my $str = "    {FT_cipher, \"$cmd\", enc_main, enc_options},\n";
    (my $algo = $cmd) =~ s/-.*//g;
    if ($cmd eq "zlib") {
        print "#ifdef ZLIB\n${str}#endif\n";
    } elsif (grep { $algo eq $_ } @disablables) {
        print "#ifndef OPENSSL_NO_" . uc($algo) . "\n${str}#endif\n";
    } elsif (my $disabler = $cipher_disabler{$algo}) {
        print "#ifndef OPENSSL_NO_" . uc($disabler) . "\n${str}#endif\n";
    } else {
        print $str;
    }
}

print "    {0, NULL, NULL}\n};\n";
print "#endif\n";


#! /usr/bin/env perl
# -*- mode: perl; -*-
# Copyright 2016-2018 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

# This is a collection of extra attributes to be used as input for creating
# shared libraries, currently on any Unix variant, including Unix like
# environments on Windows.

sub detect_gnu_ld {
    my @lines =
        `$config{CROSS_COMPILE}$config{CC} -Wl,-V /dev/null 2>&1`;
    return grep /^GNU ld/, @lines;
}
sub detect_gnu_cc {
    my @lines =
        `$config{CROSS_COMPILE}$config{CC} -v 2>&1`;
    return grep /gcc/, @lines;
}

my %shared_info;
%shared_info = (
    'gnu-shared' => {
        shared_ldflag         => '-shared -Wl,-Bsymbolic',
        shared_sonameflag     => '-Wl,-soname=',
    },
    'linux-shared' => sub {
        return {
            %{$shared_info{'gnu-shared'}},
            shared_defflag    => '-Wl,--version-script=',
        };
    },
    'bsd-gcc-shared' => sub { return $shared_info{'linux-shared'}; },
    'bsd-shared' => sub {
        return $shared_info{'gnu-shared'} if detect_gnu_ld();
        return {
            shared_ldflag     => '-shared -nostdlib',
        };
    },
    'darwin-shared' => {
        module_ldflags        => '-bundle',
        shared_ldflag         => '-dynamiclib -current_version $(SHLIB_VERSION_NUMBER) -compatibility_version $(SHLIB_VERSION_NUMBER)',
        shared_sonameflag     => '-install_name $(INSTALLTOP)/$(LIBDIR)/',
    },
    'cygwin-shared' => {
        shared_ldflag         => '-shared -Wl,--enable-auto-image-base',
        shared_impflag        => '-Wl,--out-implib=',
    },
    'mingw-shared' => sub {
        return {
            %{$shared_info{'cygwin-shared'}},
            # def_flag made to empty string so  it still generates
            # something
            shared_defflag    => '',
        };
    },
    'alpha-osf1-shared' => sub {
        return $shared_info{'gnu-shared'} if detect_gnu_ld();
        return {
            module_ldflags    => '-shared -Wl,-Bsymbolic',
            shared_ldflag     => '-shared -Wl,-Bsymbolic -set_version $(SHLIB_VERSION_NUMBER)',
        };
    },
    'svr3-shared' => sub {
        return $shared_info{'gnu-shared'} if detect_gnu_ld();
        return {
            shared_ldflag     => '-G',
            shared_sonameflag => '-h ',
        };
    },
    'svr5-shared' => sub {
        return $shared_info{'gnu-shared'} if detect_gnu_ld();
        return {
            shared_ldflag     => detect_gnu_cc() ? '-shared' : '-G',
            shared_sonameflag => '-h ',
        };
    },
);


#! /usr/bin/env perl
# Copyright 2010-2020 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

$output = pop;
open STDOUT,">$output";

print <<'___';
.text

.set	noat

.globl	OPENSSL_cpuid_setup
.ent	OPENSSL_cpuid_setup
OPENSSL_cpuid_setup:
	.frame	$30,0,$26
	.prologue 0
	ret	($26)
.end	OPENSSL_cpuid_setup

.globl	OPENSSL_wipe_cpu
.ent	OPENSSL_wipe_cpu
OPENSSL_wipe_cpu:
	.frame	$30,0,$26
	.prologue 0
	clr	$1
	clr	$2
	clr	$3
	clr	$4
	clr	$5
	clr	$6
	clr	$7
	clr	$8
	clr	$16
	clr	$17
	clr	$18
	clr	$19
	clr	$20
	clr	$21
	clr	$22
	clr	$23
	clr	$24
	clr	$25
	clr	$27
	clr	$at
	clr	$29
	fclr	$f0
	fclr	$f1
	fclr	$f10
	fclr	$f11
	fclr	$f12
	fclr	$f13
	fclr	$f14
	fclr	$f15
	fclr	$f16
	fclr	$f17
	fclr	$f18
	fclr	$f19
	fclr	$f20
	fclr	$f21
	fclr	$f22
	fclr	$f23
	fclr	$f24
	fclr	$f25
	fclr	$f26
	fclr	$f27
	fclr	$f28
	fclr	$f29
	fclr	$f30
	mov	$sp,$0
	ret	($26)
.end	OPENSSL_wipe_cpu

.globl	OPENSSL_atomic_add
.ent	OPENSSL_atomic_add
OPENSSL_atomic_add:
	.frame	$30,0,$26
	.prologue 0
1:	ldl_l	$0,0($16)
	addl	$0,$17,$1
	stl_c	$1,0($16)
	beq	$1,1b
	addl	$0,$17,$0
	ret	($26)
.end	OPENSSL_atomic_add

.globl	OPENSSL_rdtsc
.ent	OPENSSL_rdtsc
OPENSSL_rdtsc:
	.frame	$30,0,$26
	.prologue 0
	rpcc	$0
	ret	($26)
.end	OPENSSL_rdtsc

.globl	OPENSSL_cleanse
.ent	OPENSSL_cleanse
OPENSSL_cleanse:
	.frame	$30,0,$26
	.prologue 0
	beq	$17,.Ldone
	and	$16,7,$0
	bic	$17,7,$at
	beq	$at,.Little
	beq	$0,.Laligned

.Little:
	subq	$0,8,$0
	ldq_u	$1,0($16)
	mov	$16,$2
.Lalign:
	mskbl	$1,$16,$1
	lda	$16,1($16)
	subq	$17,1,$17
	addq	$0,1,$0
	beq	$17,.Lout
	bne	$0,.Lalign
.Lout:	stq_u	$1,0($2)
	beq	$17,.Ldone
	bic	$17,7,$at
	beq	$at,.Little

.Laligned:
	stq	$31,0($16)
	subq	$17,8,$17
	lda	$16,8($16)
	bic	$17,7,$at
	bne	$at,.Laligned
	bne	$17,.Little
.Ldone: ret	($26)
.end	OPENSSL_cleanse

.globl	CRYPTO_memcmp
.ent	CRYPTO_memcmp
CRYPTO_memcmp:
	.frame	$30,0,$26
	.prologue 0
	xor	$0,$0,$0
	beq	$18,.Lno_data

	xor	$1,$1,$1
	nop
.Loop_cmp:
	ldq_u	$2,0($16)
	subq	$18,1,$18
	ldq_u	$3,0($17)
	extbl	$2,$16,$2
	lda	$16,1($16)
	extbl	$3,$17,$3
	lda	$17,1($17)
	xor	$3,$2,$2
	or	$2,$0,$0
	bne	$18,.Loop_cmp

	subq	$31,$0,$0
	srl	$0,63,$0
.Lno_data:
	ret	($26)
.end	CRYPTO_memcmp
___
{
my ($out,$cnt,$max)=("\$16","\$17","\$18");
my ($tick,$lasttick)=("\$19","\$20");
my ($diff,$lastdiff)=("\$21","\$22");
my ($v0,$ra,$sp,$zero)=("\$0","\$26","\$30","\$31");

print <<___;
.globl	OPENSSL_instrument_bus
.ent	OPENSSL_instrument_bus
OPENSSL_instrument_bus:
	.frame	$sp,0,$ra
	.prologue 0
	mov	$cnt,$v0

	rpcc	$lasttick
	mov	0,$diff

	ecb	($out)
	ldl_l	$tick,0($out)
	addl	$diff,$tick,$tick
	mov	$tick,$diff
	stl_c	$tick,0($out)
	stl	$diff,0($out)

.Loop:	rpcc	$tick
	subq	$tick,$lasttick,$diff
	mov	$tick,$lasttick

	ecb	($out)
	ldl_l	$tick,0($out)
	addl	$diff,$tick,$tick
	mov	$tick,$diff
	stl_c	$tick,0($out)
	stl	$diff,0($out)

	subl	$cnt,1,$cnt
	lda	$out,4($out)
	bne	$cnt,.Loop

	ret	($ra)
.end	OPENSSL_instrument_bus

.globl	OPENSSL_instrument_bus2
.ent	OPENSSL_instrument_bus2
OPENSSL_instrument_bus2:
	.frame	$sp,0,$ra
	.prologue 0
	mov	$cnt,$v0

	rpcc	$lasttick
	mov	0,$diff

	ecb	($out)
	ldl_l	$tick,0($out)
	addl	$diff,$tick,$tick
	mov	$tick,$diff
	stl_c	$tick,0($out)
	stl	$diff,0($out)

	rpcc	$tick
	subq	$tick,$lasttick,$diff
	mov	$tick,$lasttick
	mov	$diff,$lastdiff
.Loop2:
	ecb	($out)
	ldl_l	$tick,0($out)
	addl	$diff,$tick,$tick
	mov	$tick,$diff
	stl_c	$tick,0($out)
	stl	$diff,0($out)

	subl	$max,1,$max
	beq	$max,.Ldone2

	rpcc	$tick
	subq	$tick,$lasttick,$diff
	mov	$tick,$lasttick
	subq	$lastdiff,$diff,$tick
	mov	$diff,$lastdiff
	cmovne	$tick,1,$tick
	subl	$cnt,$tick,$cnt
	s4addq	$tick,$out,$out
	bne	$cnt,.Loop2

.Ldone2:
	subl	$v0,$cnt,$v0
	ret	($ra)
.end	OPENSSL_instrument_bus2
___
}

close STDOUT or die "error closing STDOUT: $!";


#! /usr/bin/env perl
# Copyright 2015-2020 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

$flavour = shift;
$output  = shift;

$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
( $xlate="${dir}perlasm/arm-xlate.pl" and -f $xlate) or
die "can't locate arm-xlate.pl";

open OUT,"| \"$^X\" $xlate $flavour $output";
*STDOUT=*OUT;

$code.=<<___;
#include "arm_arch.h"

.text
.arch	armv8-a+crypto

.align	5
.globl	_armv7_neon_probe
.type	_armv7_neon_probe,%function
_armv7_neon_probe:
	orr	v15.16b, v15.16b, v15.16b
	ret
.size	_armv7_neon_probe,.-_armv7_neon_probe

.globl	_armv7_tick
.type	_armv7_tick,%function
_armv7_tick:
#ifdef	__APPLE__
	mrs	x0, CNTPCT_EL0
#else
	mrs	x0, CNTVCT_EL0
#endif
	ret
.size	_armv7_tick,.-_armv7_tick

.globl	_armv8_aes_probe
.type	_armv8_aes_probe,%function
_armv8_aes_probe:
	aese	v0.16b, v0.16b
	ret
.size	_armv8_aes_probe,.-_armv8_aes_probe

.globl	_armv8_sha1_probe
.type	_armv8_sha1_probe,%function
_armv8_sha1_probe:
	sha1h	s0, s0
	ret
.size	_armv8_sha1_probe,.-_armv8_sha1_probe

.globl	_armv8_sha256_probe
.type	_armv8_sha256_probe,%function
_armv8_sha256_probe:
	sha256su0	v0.4s, v0.4s
	ret
.size	_armv8_sha256_probe,.-_armv8_sha256_probe

.globl	_armv8_pmull_probe
.type	_armv8_pmull_probe,%function
_armv8_pmull_probe:
	pmull	v0.1q, v0.1d, v0.1d
	ret
.size	_armv8_pmull_probe,.-_armv8_pmull_probe

.globl	_armv8_sha512_probe
.type	_armv8_sha512_probe,%function
_armv8_sha512_probe:
	.long	0xcec08000	// sha512su0	v0.2d,v0.2d
	ret
.size	_armv8_sha512_probe,.-_armv8_sha512_probe

.globl	OPENSSL_cleanse
.type	OPENSSL_cleanse,%function
.align	5
OPENSSL_cleanse:
	cbz	x1,.Lret	// len==0?
	cmp	x1,#15
	b.hi	.Lot		// len>15
	nop
.Little:
	strb	wzr,[x0],#1	// store byte-by-byte
	subs	x1,x1,#1
	b.ne	.Little
.Lret:	ret

.align	4
.Lot:	tst	x0,#7
	b.eq	.Laligned	// inp is aligned
	strb	wzr,[x0],#1	// store byte-by-byte
	sub	x1,x1,#1
	b	.Lot

.align	4
.Laligned:
	str	xzr,[x0],#8	// store word-by-word
	sub	x1,x1,#8
	tst	x1,#-8
	b.ne	.Laligned	// len>=8
	cbnz	x1,.Little	// len!=0?
	ret
.size	OPENSSL_cleanse,.-OPENSSL_cleanse

.globl	CRYPTO_memcmp
.type	CRYPTO_memcmp,%function
.align	4
CRYPTO_memcmp:
	eor	w3,w3,w3
	cbz	x2,.Lno_data	// len==0?
	cmp	x2,#16
	b.ne	.Loop_cmp
	ldp	x8,x9,[x0]
	ldp	x10,x11,[x1]
	eor	x8,x8,x10
	eor	x9,x9,x11
	orr	x8,x8,x9
	mov	x0,#1
	cmp	x8,#0
	csel	x0,xzr,x0,eq
	ret

.align	4
.Loop_cmp:
	ldrb	w4,[x0],#1
	ldrb	w5,[x1],#1
	eor	w4,w4,w5
	orr	w3,w3,w4
	subs	x2,x2,#1
	b.ne	.Loop_cmp

.Lno_data:
	neg	w0,w3
	lsr	w0,w0,#31
	ret
.size	CRYPTO_memcmp,.-CRYPTO_memcmp
___

print $code;
close STDOUT or die "error closing STDOUT: $!";


#! /usr/bin/env perl
# Copyright 2015-2020 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

$flavour = shift;
$output  = shift;

$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
( $xlate="${dir}perlasm/arm-xlate.pl" and -f $xlate) or
die "can't locate arm-xlate.pl";

open OUT,"| \"$^X\" $xlate $flavour $output";
*STDOUT=*OUT;

$code.=<<___;
#include "arm_arch.h"

.text
#if defined(__thumb2__) && !defined(__APPLE__)
.syntax	unified
.thumb
#else
.code	32
#undef	__thumb2__
#endif

.align	5
.global	OPENSSL_atomic_add
.type	OPENSSL_atomic_add,%function
OPENSSL_atomic_add:
#if __ARM_ARCH__>=6
.Ladd:	ldrex	r2,[r0]
	add	r3,r2,r1
	strex	r2,r3,[r0]
	cmp	r2,#0
	bne	.Ladd
	mov	r0,r3
	bx	lr
#else
	stmdb	sp!,{r4-r6,lr}
	ldr	r2,.Lspinlock
	adr	r3,.Lspinlock
	mov	r4,r0
	mov	r5,r1
	add	r6,r3,r2	@ &spinlock
	b	.+8
.Lspin:	bl	sched_yield
	mov	r0,#-1
	swp	r0,r0,[r6]
	cmp	r0,#0
	bne	.Lspin

	ldr	r2,[r4]
	add	r2,r2,r5
	str	r2,[r4]
	str	r0,[r6]		@ release spinlock
	ldmia	sp!,{r4-r6,lr}
	tst	lr,#1
	moveq	pc,lr
	.word	0xe12fff1e	@ bx	lr
#endif
.size	OPENSSL_atomic_add,.-OPENSSL_atomic_add

.global	OPENSSL_cleanse
.type	OPENSSL_cleanse,%function
OPENSSL_cleanse:
	eor	ip,ip,ip
	cmp	r1,#7
#ifdef	__thumb2__
	itt	hs
#endif
	subhs	r1,r1,#4
	bhs	.Lot
	cmp	r1,#0
	beq	.Lcleanse_done
.Little:
	strb	ip,[r0],#1
	subs	r1,r1,#1
	bhi	.Little
	b	.Lcleanse_done

.Lot:	tst	r0,#3
	beq	.Laligned
	strb	ip,[r0],#1
	sub	r1,r1,#1
	b	.Lot
.Laligned:
	str	ip,[r0],#4
	subs	r1,r1,#4
	bhs	.Laligned
	adds	r1,r1,#4
	bne	.Little
.Lcleanse_done:
#if __ARM_ARCH__>=5
	bx	lr
#else
	tst	lr,#1
	moveq	pc,lr
	.word	0xe12fff1e	@ bx	lr
#endif
.size	OPENSSL_cleanse,.-OPENSSL_cleanse

.global	CRYPTO_memcmp
.type	CRYPTO_memcmp,%function
.align	4
CRYPTO_memcmp:
	eor	ip,ip,ip
	cmp	r2,#0
	beq	.Lno_data
	stmdb	sp!,{r4,r5}

.Loop_cmp:
	ldrb	r4,[r0],#1
	ldrb	r5,[r1],#1
	eor	r4,r4,r5
	orr	ip,ip,r4
	subs	r2,r2,#1
	bne	.Loop_cmp

	ldmia	sp!,{r4,r5}
.Lno_data:
	rsb	r0,ip,#0
	mov	r0,r0,lsr#31
#if __ARM_ARCH__>=5
	bx	lr
#else
	tst	lr,#1
	moveq	pc,lr
	.word	0xe12fff1e	@ bx	lr
#endif
.size	CRYPTO_memcmp,.-CRYPTO_memcmp

#if __ARM_MAX_ARCH__>=7
.arch	armv7-a
.fpu	neon

.align	5
.global	_armv7_neon_probe
.type	_armv7_neon_probe,%function
_armv7_neon_probe:
	vorr	q0,q0,q0
	bx	lr
.size	_armv7_neon_probe,.-_armv7_neon_probe

.global	_armv7_tick
.type	_armv7_tick,%function
_armv7_tick:
#ifdef	__APPLE__
	mrrc	p15,0,r0,r1,c14		@ CNTPCT
#else
	mrrc	p15,1,r0,r1,c14		@ CNTVCT
#endif
	bx	lr
.size	_armv7_tick,.-_armv7_tick

.global	_armv8_aes_probe
.type	_armv8_aes_probe,%function
_armv8_aes_probe:
#if defined(__thumb2__) && !defined(__APPLE__)
	.byte	0xb0,0xff,0x00,0x03	@ aese.8	q0,q0
#else
	.byte	0x00,0x03,0xb0,0xf3	@ aese.8	q0,q0
#endif
	bx	lr
.size	_armv8_aes_probe,.-_armv8_aes_probe

.global	_armv8_sha1_probe
.type	_armv8_sha1_probe,%function
_armv8_sha1_probe:
#if defined(__thumb2__) && !defined(__APPLE__)
	.byte	0x00,0xef,0x40,0x0c	@ sha1c.32	q0,q0,q0
#else
	.byte	0x40,0x0c,0x00,0xf2	@ sha1c.32	q0,q0,q0
#endif
	bx	lr
.size	_armv8_sha1_probe,.-_armv8_sha1_probe

.global	_armv8_sha256_probe
.type	_armv8_sha256_probe,%function
_armv8_sha256_probe:
#if defined(__thumb2__) && !defined(__APPLE__)
	.byte	0x00,0xff,0x40,0x0c	@ sha256h.32	q0,q0,q0
#else
	.byte	0x40,0x0c,0x00,0xf3	@ sha256h.32	q0,q0,q0
#endif
	bx	lr
.size	_armv8_sha256_probe,.-_armv8_sha256_probe
.global	_armv8_pmull_probe
.type	_armv8_pmull_probe,%function
_armv8_pmull_probe:
#if defined(__thumb2__) && !defined(__APPLE__)
	.byte	0xa0,0xef,0x00,0x0e	@ vmull.p64	q0,d0,d0
#else
	.byte	0x00,0x0e,0xa0,0xf2	@ vmull.p64	q0,d0,d0
#endif
	bx	lr
.size	_armv8_pmull_probe,.-_armv8_pmull_probe
#endif

.global	OPENSSL_wipe_cpu
.type	OPENSSL_wipe_cpu,%function
OPENSSL_wipe_cpu:
#if __ARM_MAX_ARCH__>=7
	ldr	r0,.LOPENSSL_armcap
	adr	r1,.LOPENSSL_armcap
	ldr	r0,[r1,r0]
#ifdef	__APPLE__
	ldr	r0,[r0]
#endif
#endif
	eor	r2,r2,r2
	eor	r3,r3,r3
	eor	ip,ip,ip
#if __ARM_MAX_ARCH__>=7
	tst	r0,#1
	beq	.Lwipe_done
	veor	q0, q0, q0
	veor	q1, q1, q1
	veor	q2, q2, q2
	veor	q3, q3, q3
	veor	q8, q8, q8
	veor	q9, q9, q9
	veor	q10, q10, q10
	veor	q11, q11, q11
	veor	q12, q12, q12
	veor	q13, q13, q13
	veor	q14, q14, q14
	veor	q15, q15, q15
.Lwipe_done:
#endif
	mov	r0,sp
#if __ARM_ARCH__>=5
	bx	lr
#else
	tst	lr,#1
	moveq	pc,lr
	.word	0xe12fff1e	@ bx	lr
#endif
.size	OPENSSL_wipe_cpu,.-OPENSSL_wipe_cpu

.global	OPENSSL_instrument_bus
.type	OPENSSL_instrument_bus,%function
OPENSSL_instrument_bus:
	eor	r0,r0,r0
#if __ARM_ARCH__>=5
	bx	lr
#else
	tst	lr,#1
	moveq	pc,lr
	.word	0xe12fff1e	@ bx	lr
#endif
.size	OPENSSL_instrument_bus,.-OPENSSL_instrument_bus

.global	OPENSSL_instrument_bus2
.type	OPENSSL_instrument_bus2,%function
OPENSSL_instrument_bus2:
	eor	r0,r0,r0
#if __ARM_ARCH__>=5
	bx	lr
#else
	tst	lr,#1
	moveq	pc,lr
	.word	0xe12fff1e	@ bx	lr
#endif
.size	OPENSSL_instrument_bus2,.-OPENSSL_instrument_bus2

.align	5
#if __ARM_MAX_ARCH__>=7
.LOPENSSL_armcap:
.word	OPENSSL_armcap_P-.
#endif
#if __ARM_ARCH__>=6
.align	5
#else
.Lspinlock:
.word	atomic_add_spinlock-.Lspinlock
.align	5

.data
.align	2
atomic_add_spinlock:
.word	0
#endif

.comm	OPENSSL_armcap_P,4,4
.hidden	OPENSSL_armcap_P
___

print $code;
close STDOUT or die "error closing STDOUT: $!";


#! /usr/bin/env perl
# Copyright 2012-2020 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

while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {}
open STDOUT,">$output";

$code.=<<___;
	.text

	.if	.ASSEMBLER_VERSION<7000000
	.asg	0,__TI_EABI__
	.endif
	.if	__TI_EABI__
	.asg	OPENSSL_rdtsc,_OPENSSL_rdtsc
	.asg	OPENSSL_cleanse,_OPENSSL_cleanse
	.asg	CRYPTO_memcmp,_CRYPTO_memcmp
	.asg	OPENSSL_atomic_add,_OPENSSL_atomic_add
	.asg	OPENSSL_wipe_cpu,_OPENSSL_wipe_cpu
	.asg	OPENSSL_instrument_bus,_OPENSSL_instrument_bus
	.asg	OPENSSL_instrument_bus2,_OPENSSL_instrument_bus2
	.endif

	.asg	B3,RA

	.global	_OPENSSL_rdtsc
_OPENSSL_rdtsc:
	.asmfunc
	B	RA
	MVC	TSCL,B0
	MVC	TSCH,B1
  [!B0]	MVC	B0,TSCL		; start TSC
	MV	B0,A4
	MV	B1,A5
	.endasmfunc

	.global	_OPENSSL_cleanse
_OPENSSL_cleanse:
	.asmfunc
	ZERO	A3:A2
||	ZERO	B2
||	SHRU	B4,3,B0		; is length >= 8
||	ADD	1,A4,B6
  [!B0]	BNOP	RA
||	ZERO	A1
||	ZERO	B1
   [B0]	MVC	B0,ILC
||[!B0]	CMPLT	0,B4,A1
||[!B0]	CMPLT	1,B4,B1
   [A1]	STB	A2,*A4++[2]
|| [B1] STB	B2,*B6++[2]
||[!B0]	CMPLT	2,B4,A1
||[!B0]	CMPLT	3,B4,B1
   [A1]	STB	A2,*A4++[2]
|| [B1] STB	B2,*B6++[2]
||[!B0]	CMPLT	4,B4,A1
||[!B0]	CMPLT	5,B4,B1
   [A1]	STB	A2,*A4++[2]
|| [B1] STB	B2,*B6++[2]
||[!B0]	CMPLT	6,B4,A1
   [A1]	STB	A2,*A4++[2]

	SPLOOP	1
	STNDW	A3:A2,*A4++
||	SUB	B4,8,B4
	SPKERNEL

	MV	B4,B0		; remaining bytes
||	ADD	1,A4,B6
||	BNOP	RA
   [B0]	CMPLT	0,B0,A1
|| [B0]	CMPLT	1,B0,B1
   [A1]	STB	A2,*A4++[2]
|| [B1] STB	B2,*B6++[2]
|| [B0]	CMPLT	2,B0,A1
|| [B0]	CMPLT	3,B0,B1
   [A1]	STB	A2,*A4++[2]
|| [B1] STB	B2,*B6++[2]
|| [B0]	CMPLT	4,B0,A1
|| [B0]	CMPLT	5,B0,B1
   [A1]	STB	A2,*A4++[2]
|| [B1] STB	B2,*B6++[2]
|| [B0]	CMPLT	6,B0,A1
   [A1]	STB	A2,*A4++[2]
	.endasmfunc

	.global	_CRYPTO_memcmp
_CRYPTO_memcmp:
	.asmfunc
	MV	A6,B0
  [!B0]	BNOP	RA
||[!B0]	ZERO	A4
   [B0]	MVC	B0,ILC
|| [B0]	ZERO	A0
	NOP	4

	SPLOOP	1
	LDBU	*A4++,A1
||	LDBU	*B4++,B1
	NOP	4
	XOR.L	B1,A1,A2
	SPKERNEL 1,0
||	OR.S	A2,A0,A0

	BNOP	RA,3
	ZERO.L	A4
  [A0]	MVK	1,A4
	.endasmfunc

	.global	_OPENSSL_atomic_add
_OPENSSL_atomic_add:
	.asmfunc
	MV	A4,B0
atomic_add?:
	LL	*B0,B5
	NOP	4
	ADD	B4,B5,B5
	SL	B5,*B0
	CMTL	*B0,B1
	NOP	4
  [!B1]	B	atomic_add?
   [B1]	BNOP	RA,4
	MV	B5,A4
	.endasmfunc

	.global	_OPENSSL_wipe_cpu
_OPENSSL_wipe_cpu:
	.asmfunc
	ZERO	A0
||	ZERO	B0
||	ZERO	A1
||	ZERO	B1
	ZERO	A3:A2
||	MVD	B0,B2
||	ZERO	A4
||	ZERO	B4
||	ZERO	A5
||	ZERO	B5
||	BNOP	RA
	ZERO	A7:A6
||	ZERO	B7:B6
||	ZERO	A8
||	ZERO	B8
||	ZERO	A9
||	ZERO	B9
	ZERO	A17:A16
||	ZERO	B17:B16
||	ZERO	A18
||	ZERO	B18
||	ZERO	A19
||	ZERO	B19
	ZERO	A21:A20
||	ZERO	B21:B20
||	ZERO	A22
||	ZERO	B22
||	ZERO	A23
||	ZERO	B23
	ZERO	A25:A24
||	ZERO	B25:B24
||	ZERO	A26
||	ZERO	B26
||	ZERO	A27
||	ZERO	B27
	ZERO	A29:A28
||	ZERO	B29:B28
||	ZERO	A30
||	ZERO	B30
||	ZERO	A31
||	ZERO	B31
	.endasmfunc

CLFLUSH	.macro	CONTROL,ADDR,LEN
	B	passthrough?
||	STW	ADDR,*CONTROL[0]
	STW	LEN,*CONTROL[1]
spinlock?:
	LDW	*CONTROL[1],A0
	NOP	3
passthrough?:
	NOP
  [A0]	BNOP	spinlock?,5
	.endm

	.global	_OPENSSL_instrument_bus
_OPENSSL_instrument_bus:
	.asmfunc
	MV	B4,B0			; reassign sizeof(output)
||	MV	A4,B4			; reassign output
||	MVK	0x00004030,A3
	MV	B0,A4			; return value
||	MVK	1,A1
||	MVKH	0x01840000,A3		; L1DWIBAR
	MVC	TSCL,B8			; collect 1st tick
||	MVK	0x00004010,A5
	MV	B8,B9			; lasttick = tick
||	MVK	0,B7			; lastdiff = 0
||	MVKH	0x01840000,A5		; L2WIBAR
	CLFLUSH	A3,B4,A1		; write-back and invalidate L1D line
	CLFLUSH	A5,B4,A1		; write-back and invalidate L2 line
	LL	*B4,B5
	NOP	4
	ADD	B7,B5,B5
	SL	B5,*B4
	CMTL	*B4,B1
	NOP	4
	STW	B5,*B4
bus_loop1?:
	MVC	TSCL,B8
|| [B0]	SUB	B0,1,B0
	SUB	B8,B9,B7		; lastdiff = tick - lasttick
||	MV	B8,B9			; lasttick = tick
	CLFLUSH	A3,B4,A1		; write-back and invalidate L1D line
	CLFLUSH	A5,B4,A1		; write-back and invalidate L2 line
	LL	*B4,B5
	NOP	4
	ADD	B7,B5,B5
	SL	B5,*B4
	CMTL	*B4,B1
	STW	B5,*B4			; [!B1] is removed to flatten samples
||	ADDK	4,B4
|| [B0]	BNOP	bus_loop1?,5

	BNOP	RA,5
	.endasmfunc

	.global	_OPENSSL_instrument_bus2
_OPENSSL_instrument_bus2:
	.asmfunc
	MV	A6,B0			; reassign max
||	MV	B4,A6			; reassign sizeof(output)
||	MVK	0x00004030,A3
	MV	A4,B4			; reassign output
||	MVK	0,A4			; return value
||	MVK	1,A1
||	MVKH	0x01840000,A3		; L1DWIBAR

	MVC	TSCL,B8			; collect 1st tick
||	MVK	0x00004010,A5
	MV	B8,B9			; lasttick = tick
||	MVK	0,B7			; lastdiff = 0
||	MVKH	0x01840000,A5		; L2WIBAR
	CLFLUSH	A3,B4,A1		; write-back and invalidate L1D line
	CLFLUSH	A5,B4,A1		; write-back and invalidate L2 line
	LL	*B4,B5
	NOP	4
	ADD	B7,B5,B5
	SL	B5,*B4
	CMTL	*B4,B1
	NOP	4
	STW	B5,*B4

	MVC	TSCL,B8			; collect 1st diff
	SUB	B8,B9,B7		; lastdiff = tick - lasttick
||	MV	B8,B9			; lasttick = tick
||	SUB	B0,1,B0
bus_loop2?:
	CLFLUSH	A3,B4,A1		; write-back and invalidate L1D line
	CLFLUSH	A5,B4,A1		; write-back and invalidate L2 line
	LL	*B4,B5
	NOP	4
	ADD	B7,B5,B5
	SL	B5,*B4
	CMTL	*B4,B1
	STW	B5,*B4			; [!B1] is removed to flatten samples
||[!B0]	BNOP	bus_loop2_done?,2
||	SUB	B0,1,B0
	MVC	TSCL,B8
	SUB	B8,B9,B8
||	MV	B8,B9
	CMPEQ	B8,B7,B2
||	MV	B8,B7
  [!B2]	ADDAW	B4,1,B4
||[!B2]	ADDK	1,A4
	CMPEQ	A4,A6,A2
  [!A2]	BNOP	bus_loop2?,5

bus_loop2_done?:
	BNOP	RA,5
	.endasmfunc
___

print $code;
close STDOUT or die "error closing STDOUT: $!";


#! /usr/bin/env perl
# Copyright 2009-2020 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

$flavour = shift;
$output = shift;
open STDOUT,">$output";

if ($flavour =~ /64/) {
	$LEVEL		="2.0W";
	$SIZE_T		=8;
	$ST		="std";
} else {
	$LEVEL		="1.1";
	$SIZE_T		=4;
	$ST		="stw";
}

$rp="%r2";
$sp="%r30";
$rv="%r28";

$code=<<___;
	.LEVEL	$LEVEL
	.SPACE	\$TEXT\$
	.SUBSPA	\$CODE\$,QUAD=0,ALIGN=8,ACCESS=0x2C,CODE_ONLY

	.EXPORT	OPENSSL_cpuid_setup,ENTRY
	.ALIGN	8
OPENSSL_cpuid_setup
	.PROC
	.CALLINFO	NO_CALLS
	.ENTRY
	bv	($rp)
	.EXIT
	nop
	.PROCEND

	.EXPORT	OPENSSL_rdtsc,ENTRY
	.ALIGN	8
OPENSSL_rdtsc
	.PROC
	.CALLINFO	NO_CALLS
	.ENTRY
	mfctl	%cr16,$rv
	bv	($rp)
	.EXIT
	nop
	.PROCEND

	.EXPORT	OPENSSL_wipe_cpu,ENTRY
	.ALIGN	8
OPENSSL_wipe_cpu
	.PROC
	.CALLINFO	NO_CALLS
	.ENTRY
	xor		%r0,%r0,%r1
	fcpy,dbl	%fr0,%fr4
	xor		%r0,%r0,%r19
	fcpy,dbl	%fr0,%fr5
	xor		%r0,%r0,%r20
	fcpy,dbl	%fr0,%fr6
	xor		%r0,%r0,%r21
	fcpy,dbl	%fr0,%fr7
	xor		%r0,%r0,%r22
	fcpy,dbl	%fr0,%fr8
	xor		%r0,%r0,%r23
	fcpy,dbl	%fr0,%fr9
	xor		%r0,%r0,%r24
	fcpy,dbl	%fr0,%fr10
	xor		%r0,%r0,%r25
	fcpy,dbl	%fr0,%fr11
	xor		%r0,%r0,%r26
	fcpy,dbl	%fr0,%fr22
	xor		%r0,%r0,%r29
	fcpy,dbl	%fr0,%fr23
	xor		%r0,%r0,%r31
	fcpy,dbl	%fr0,%fr24
	fcpy,dbl	%fr0,%fr25
	fcpy,dbl	%fr0,%fr26
	fcpy,dbl	%fr0,%fr27
	fcpy,dbl	%fr0,%fr28
	fcpy,dbl	%fr0,%fr29
	fcpy,dbl	%fr0,%fr30
	fcpy,dbl	%fr0,%fr31
	bv		($rp)
	.EXIT
	ldo		0($sp),$rv
	.PROCEND
___
{
my $inp="%r26";
my $len="%r25";

$code.=<<___;
	.EXPORT	OPENSSL_cleanse,ENTRY,ARGW0=GR,ARGW1=GR
	.ALIGN	8
OPENSSL_cleanse
	.PROC
	.CALLINFO	NO_CALLS
	.ENTRY
	cmpib,*=	0,$len,L\$done
	nop
	cmpib,*>>=	15,$len,L\$ittle
	ldi		$SIZE_T-1,%r1

L\$align
	and,*<>		$inp,%r1,%r28
	b,n		L\$aligned
	stb		%r0,0($inp)
	ldo		-1($len),$len
	b		L\$align
	ldo		1($inp),$inp

L\$aligned
	andcm		$len,%r1,%r28
L\$ot
	$ST		%r0,0($inp)
	addib,*<>	-$SIZE_T,%r28,L\$ot
	ldo		$SIZE_T($inp),$inp

	and,*<>		$len,%r1,$len
	b,n		L\$done
L\$ittle
	stb		%r0,0($inp)
	addib,*<>	-1,$len,L\$ittle
	ldo		1($inp),$inp
L\$done
	bv		($rp)
	.EXIT
	nop
	.PROCEND
___
}
{
my ($in1,$in2,$len)=("%r26","%r25","%r24");

$code.=<<___;
	.EXPORT	CRYPTO_memcmp,ENTRY,ARGW0=GR,ARGW1=GR,ARGW1=GR
	.ALIGN	8
CRYPTO_memcmp
	.PROC
	.CALLINFO	NO_CALLS
	.ENTRY
	cmpib,*=	0,$len,L\$no_data
	xor		$rv,$rv,$rv

L\$oop_cmp
	ldb		0($in1),%r19
	ldb		0($in2),%r20
	ldo		1($in1),$in1
	ldo		1($in2),$in2
	xor		%r19,%r20,%r29
	addib,*<>	-1,$len,L\$oop_cmp
	or		%r29,$rv,$rv

	sub		%r0,$rv,%r29
	extru		%r29,0,1,$rv
L\$no_data
	bv		($rp)
	.EXIT
	nop
	.PROCEND
___
}
{
my ($out,$cnt,$max)=("%r26","%r25","%r24");
my ($tick,$lasttick)=("%r23","%r22");
my ($diff,$lastdiff)=("%r21","%r20");

$code.=<<___;
	.EXPORT	OPENSSL_instrument_bus,ENTRY,ARGW0=GR,ARGW1=GR
	.ALIGN	8
OPENSSL_instrument_bus
	.PROC
	.CALLINFO	NO_CALLS
	.ENTRY
	copy		$cnt,$rv
	mfctl		%cr16,$tick
	copy		$tick,$lasttick
	ldi		0,$diff

	fdc		0($out)
	ldw		0($out),$tick
	add		$diff,$tick,$tick
	stw		$tick,0($out)
L\$oop
	mfctl		%cr16,$tick
	sub		$tick,$lasttick,$diff
	copy		$tick,$lasttick

	fdc		0($out)
	ldw		0($out),$tick
	add		$diff,$tick,$tick
	stw		$tick,0($out)

	addib,<>	-1,$cnt,L\$oop
	addi		4,$out,$out

	bv		($rp)
	.EXIT
	sub		$rv,$cnt,$rv
	.PROCEND

	.EXPORT	OPENSSL_instrument_bus2,ENTRY,ARGW0=GR,ARGW1=GR
	.ALIGN	8
OPENSSL_instrument_bus2
	.PROC
	.CALLINFO	NO_CALLS
	.ENTRY
	copy		$cnt,$rv
	sub		%r0,$cnt,$cnt

	mfctl		%cr16,$tick
	copy		$tick,$lasttick
	ldi		0,$diff

	fdc		0($out)
	ldw		0($out),$tick
	add		$diff,$tick,$tick
	stw		$tick,0($out)

	mfctl		%cr16,$tick
	sub		$tick,$lasttick,$diff
	copy		$tick,$lasttick
L\$oop2
	copy		$diff,$lastdiff
	fdc		0($out)
	ldw		0($out),$tick
	add		$diff,$tick,$tick
	stw		$tick,0($out)

	addib,=		-1,$max,L\$done2
	nop

	mfctl		%cr16,$tick
	sub		$tick,$lasttick,$diff
	copy		$tick,$lasttick
	cmpclr,<>	$lastdiff,$diff,$tick
	ldi		1,$tick

	ldi		1,%r1
	xor		%r1,$tick,$tick
	addb,<>		$tick,$cnt,L\$oop2
	shladd,l	$tick,2,$out,$out
L\$done2
	bv		($rp)
	.EXIT
	add		$rv,$cnt,$rv
	.PROCEND
___
}

if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
	=~ /GNU assembler/) {
    $gnuas = 1;
}

foreach(split("\n",$code)) {

	s/(\.LEVEL\s+2\.0)W/$1w/	if ($gnuas && $SIZE_T==8);
	s/\.SPACE\s+\$TEXT\$/.text/	if ($gnuas && $SIZE_T==8);
	s/\.SUBSPA.*//			if ($gnuas && $SIZE_T==8);
	s/cmpib,\*/comib,/		if ($SIZE_T==4);
	s/,\*/,/			if ($SIZE_T==4);
	s/\bbv\b/bve/			if ($SIZE_T==8);

	print $_,"\n";
}
close STDOUT or die "error closing STDOUT: $!";


#! /usr/bin/env perl
# Copyright 2007-2020 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

$flavour = shift;

$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 ".shift || die "can't call $xlate: $!";

if ($flavour=~/64/) {
    $CMPLI="cmpldi";
    $SHRLI="srdi";
    $SIGNX="extsw";
} else {
    $CMPLI="cmplwi";
    $SHRLI="srwi";
    $SIGNX="mr";
}

$code=<<___;
.machine	"any"
.text

.globl	.OPENSSL_fpu_probe
.align	4
.OPENSSL_fpu_probe:
	fmr	f0,f0
	blr
	.long	0
	.byte	0,12,0x14,0,0,0,0,0
.size	.OPENSSL_fpu_probe,.-.OPENSSL_fpu_probe
.globl	.OPENSSL_ppc64_probe
.align	4
.OPENSSL_ppc64_probe:
	fcfid	f1,f1
	extrdi	r0,r0,32,0
	blr
	.long	0
	.byte	0,12,0x14,0,0,0,0,0
.size	.OPENSSL_ppc64_probe,.-.OPENSSL_ppc64_probe

.globl	.OPENSSL_altivec_probe
.align	4
.OPENSSL_altivec_probe:
	.long	0x10000484	# vor	v0,v0,v0
	blr
	.long	0
	.byte	0,12,0x14,0,0,0,0,0
.size	.OPENSSL_altivec_probe,.-..OPENSSL_altivec_probe

.globl	.OPENSSL_crypto207_probe
.align	4
.OPENSSL_crypto207_probe:
	lvx_u	v0,0,r1
	vcipher	v0,v0,v0
	blr
	.long	0
	.byte	0,12,0x14,0,0,0,0,0
.size	.OPENSSL_crypto207_probe,.-.OPENSSL_crypto207_probe

.globl	.OPENSSL_madd300_probe
.align	4
.OPENSSL_madd300_probe:
	xor	r0,r0,r0
	maddld	r3,r0,r0,r0
	maddhdu	r3,r0,r0,r0
	blr
	.long	0
	.byte	0,12,0x14,0,0,0,0,0

.globl	.OPENSSL_wipe_cpu
.align	4
.OPENSSL_wipe_cpu:
	xor	r0,r0,r0
	fmr	f0,f31
	fmr	f1,f31
	fmr	f2,f31
	mr	r3,r1
	fmr	f3,f31
	xor	r4,r4,r4
	fmr	f4,f31
	xor	r5,r5,r5
	fmr	f5,f31
	xor	r6,r6,r6
	fmr	f6,f31
	xor	r7,r7,r7
	fmr	f7,f31
	xor	r8,r8,r8
	fmr	f8,f31
	xor	r9,r9,r9
	fmr	f9,f31
	xor	r10,r10,r10
	fmr	f10,f31
	xor	r11,r11,r11
	fmr	f11,f31
	xor	r12,r12,r12
	fmr	f12,f31
	fmr	f13,f31
	blr
	.long	0
	.byte	0,12,0x14,0,0,0,0,0
.size	.OPENSSL_wipe_cpu,.-.OPENSSL_wipe_cpu

.globl	.OPENSSL_atomic_add
.align	4
.OPENSSL_atomic_add:
Ladd:	lwarx	r5,0,r3
	add	r0,r4,r5
	stwcx.	r0,0,r3
	bne-	Ladd
	$SIGNX	r3,r0
	blr
	.long	0
	.byte	0,12,0x14,0,0,0,2,0
	.long	0
.size	.OPENSSL_atomic_add,.-.OPENSSL_atomic_add

.globl	.OPENSSL_rdtsc_mftb
.align	4
.OPENSSL_rdtsc_mftb:
	mftb	r3
	blr
	.long	0
	.byte	0,12,0x14,0,0,0,0,0
.size	.OPENSSL_rdtsc_mftb,.-.OPENSSL_rdtsc_mftb

.globl	.OPENSSL_rdtsc_mfspr268
.align	4
.OPENSSL_rdtsc_mfspr268:
	mfspr	r3,268
	blr
	.long	0
	.byte	0,12,0x14,0,0,0,0,0
.size	.OPENSSL_rdtsc_mfspr268,.-.OPENSSL_rdtsc_mfspr268

.globl	.OPENSSL_cleanse
.align	4
.OPENSSL_cleanse:
	$CMPLI	r4,7
	li	r0,0
	bge	Lot
	$CMPLI	r4,0
	beqlr-
Little:	mtctr	r4
	stb	r0,0(r3)
	addi	r3,r3,1
	bdnz	\$-8
	blr
Lot:	andi.	r5,r3,3
	beq	Laligned
	stb	r0,0(r3)
	subi	r4,r4,1
	addi	r3,r3,1
	b	Lot
Laligned:
	$SHRLI	r5,r4,2
	mtctr	r5
	stw	r0,0(r3)
	addi	r3,r3,4
	bdnz	\$-8
	andi.	r4,r4,3
	bne	Little
	blr
	.long	0
	.byte	0,12,0x14,0,0,0,2,0
	.long	0
.size	.OPENSSL_cleanse,.-.OPENSSL_cleanse

globl	.CRYPTO_memcmp
.align	4
.CRYPTO_memcmp:
	$CMPLI	r5,0
	li	r0,0
	beq	Lno_data
	mtctr	r5
Loop_cmp:
	lbz	r6,0(r3)
	addi	r3,r3,1
	lbz	r7,0(r4)
	addi	r4,r4,1
	xor	r6,r6,r7
	or	r0,r0,r6
	bdnz	Loop_cmp

Lno_data:
	li	r3,0
	sub	r3,r3,r0
	extrwi	r3,r3,1,0
	blr
	.long	0
	.byte	0,12,0x14,0,0,0,3,0
	.long	0
.size	.CRYPTO_memcmp,.-.CRYPTO_memcmp
___
{
my ($out,$cnt,$max)=("r3","r4","r5");
my ($tick,$lasttick)=("r6","r7");
my ($diff,$lastdiff)=("r8","r9");

$code.=<<___;
.globl	.OPENSSL_instrument_bus_mftb
.align	4
.OPENSSL_instrument_bus_mftb:
	mtctr	$cnt

	mftb	$lasttick		# collect 1st tick
	li	$diff,0

	dcbf	0,$out			# flush cache line
	lwarx	$tick,0,$out		# load and lock
	add	$tick,$tick,$diff
	stwcx.	$tick,0,$out
	stwx	$tick,0,$out

Loop:	mftb	$tick
	sub	$diff,$tick,$lasttick
	mr	$lasttick,$tick
	dcbf	0,$out			# flush cache line
	lwarx	$tick,0,$out		# load and lock
	add	$tick,$tick,$diff
	stwcx.	$tick,0,$out
	stwx	$tick,0,$out
	addi	$out,$out,4		# ++$out
	bdnz	Loop

	mr	r3,$cnt
	blr
	.long	0
	.byte	0,12,0x14,0,0,0,2,0
	.long	0
.size	.OPENSSL_instrument_bus_mftb,.-.OPENSSL_instrument_bus_mftb

.globl	.OPENSSL_instrument_bus2_mftb
.align	4
.OPENSSL_instrument_bus2_mftb:
	mr	r0,$cnt
	slwi	$cnt,$cnt,2

	mftb	$lasttick		# collect 1st tick
	li	$diff,0

	dcbf	0,$out			# flush cache line
	lwarx	$tick,0,$out		# load and lock
	add	$tick,$tick,$diff
	stwcx.	$tick,0,$out
	stwx	$tick,0,$out

	mftb	$tick			# collect 1st diff
	sub	$diff,$tick,$lasttick
	mr	$lasttick,$tick
	mr	$lastdiff,$diff
Loop2:
	dcbf	0,$out			# flush cache line
	lwarx	$tick,0,$out		# load and lock
	add	$tick,$tick,$diff
	stwcx.	$tick,0,$out
	stwx	$tick,0,$out

	addic.	$max,$max,-1
	beq	Ldone2

	mftb	$tick
	sub	$diff,$tick,$lasttick
	mr	$lasttick,$tick
	cmplw	7,$diff,$lastdiff
	mr	$lastdiff,$diff

	mfcr	$tick			# pull cr
	not	$tick,$tick		# flip bits
	rlwinm	$tick,$tick,1,29,29	# isolate flipped eq bit and scale

	sub.	$cnt,$cnt,$tick		# conditional --$cnt
	add	$out,$out,$tick		# conditional ++$out
	bne	Loop2

Ldone2:
	srwi	$cnt,$cnt,2
	sub	r3,r0,$cnt
	blr
	.long	0
	.byte	0,12,0x14,0,0,0,3,0
	.long	0
.size	.OPENSSL_instrument_bus2_mftb,.-.OPENSSL_instrument_bus2_mftb

.globl	.OPENSSL_instrument_bus_mfspr268
.align	4
.OPENSSL_instrument_bus_mfspr268:
	mtctr	$cnt

	mfspr	$lasttick,268		# collect 1st tick
	li	$diff,0

	dcbf	0,$out			# flush cache line
	lwarx	$tick,0,$out		# load and lock
	add	$tick,$tick,$diff
	stwcx.	$tick,0,$out
	stwx	$tick,0,$out

Loop3:	mfspr	$tick,268
	sub	$diff,$tick,$lasttick
	mr	$lasttick,$tick
	dcbf	0,$out			# flush cache line
	lwarx	$tick,0,$out		# load and lock
	add	$tick,$tick,$diff
	stwcx.	$tick,0,$out
	stwx	$tick,0,$out
	addi	$out,$out,4		# ++$out
	bdnz	Loop3

	mr	r3,$cnt
	blr
	.long	0
	.byte	0,12,0x14,0,0,0,2,0
	.long	0
.size	.OPENSSL_instrument_bus_mfspr268,.-.OPENSSL_instrument_bus_mfspr268

.globl	.OPENSSL_instrument_bus2_mfspr268
.align	4
.OPENSSL_instrument_bus2_mfspr268:
	mr	r0,$cnt
	slwi	$cnt,$cnt,2

	mfspr	$lasttick,268		# collect 1st tick
	li	$diff,0

	dcbf	0,$out			# flush cache line
	lwarx	$tick,0,$out		# load and lock
	add	$tick,$tick,$diff
	stwcx.	$tick,0,$out
	stwx	$tick,0,$out

	mfspr	$tick,268		# collect 1st diff
	sub	$diff,$tick,$lasttick
	mr	$lasttick,$tick
	mr	$lastdiff,$diff
Loop4:
	dcbf	0,$out			# flush cache line
	lwarx	$tick,0,$out		# load and lock
	add	$tick,$tick,$diff
	stwcx.	$tick,0,$out
	stwx	$tick,0,$out

	addic.	$max,$max,-1
	beq	Ldone4

	mfspr	$tick,268
	sub	$diff,$tick,$lasttick
	mr	$lasttick,$tick
	cmplw	7,$diff,$lastdiff
	mr	$lastdiff,$diff

	mfcr	$tick			# pull cr
	not	$tick,$tick		# flip bits
	rlwinm	$tick,$tick,1,29,29	# isolate flipped eq bit and scale

	sub.	$cnt,$cnt,$tick		# conditional --$cnt
	add	$out,$out,$tick		# conditional ++$out
	bne	Loop4

Ldone4:
	srwi	$cnt,$cnt,2
	sub	r3,r0,$cnt
	blr
	.long	0
	.byte	0,12,0x14,0,0,0,3,0
	.long	0
.size	.OPENSSL_instrument_bus2_mfspr268,.-.OPENSSL_instrument_bus2_mfspr268
___
}

$code =~ s/\`([^\`]*)\`/eval $1/gem;
print $code;
close STDOUT or die "error closing STDOUT: $!";


#! /usr/bin/env perl
# Copyright 2009-2020 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

$flavour = shift;

if ($flavour =~ /3[12]/) {
	$SIZE_T=4;
	$g="";
} else {
	$SIZE_T=8;
	$g="g";
}

while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {}
open STDOUT,">$output";

$ra="%r14";
$sp="%r15";
$stdframe=16*$SIZE_T+4*8;

$code=<<___;
#include "s390x_arch.h"

.text

.globl	OPENSSL_s390x_facilities
.type	OPENSSL_s390x_facilities,\@function
.align	16
OPENSSL_s390x_facilities:
	lghi	%r0,0
	larl	%r4,OPENSSL_s390xcap_P

	stg	%r0,S390X_STFLE+8(%r4)	# wipe capability vectors
	stg	%r0,S390X_STFLE+16(%r4)
	stg	%r0,S390X_STFLE+24(%r4)
	stg	%r0,S390X_KIMD(%r4)
	stg	%r0,S390X_KIMD+8(%r4)
	stg	%r0,S390X_KLMD(%r4)
	stg	%r0,S390X_KLMD+8(%r4)
	stg	%r0,S390X_KM(%r4)
	stg	%r0,S390X_KM+8(%r4)
	stg	%r0,S390X_KMC(%r4)
	stg	%r0,S390X_KMC+8(%r4)
	stg	%r0,S390X_KMAC(%r4)
	stg	%r0,S390X_KMAC+8(%r4)
	stg	%r0,S390X_KMCTR(%r4)
	stg	%r0,S390X_KMCTR+8(%r4)
	stg	%r0,S390X_KMO(%r4)
	stg	%r0,S390X_KMO+8(%r4)
	stg	%r0,S390X_KMF(%r4)
	stg	%r0,S390X_KMF+8(%r4)
	stg	%r0,S390X_PRNO(%r4)
	stg	%r0,S390X_PRNO+8(%r4)
	stg	%r0,S390X_KMA(%r4)
	stg	%r0,S390X_KMA+8(%r4)

	.long	0xb2b04000		# stfle	0(%r4)
	brc	8,.Ldone
	lghi	%r0,1
	.long	0xb2b04000		# stfle 0(%r4)
	brc	8,.Ldone
	lghi	%r0,2
	.long	0xb2b04000		# stfle 0(%r4)
.Ldone:
	lmg	%r2,%r3,S390X_STFLE(%r4)
	tmhl	%r2,0x4000		# check for message-security-assist
	jz	.Lret

	lghi	%r0,S390X_QUERY		# query kimd capabilities
	la	%r1,S390X_KIMD(%r4)
	.long	0xb93e0002		# kimd %r0,%r2

	lghi	%r0,S390X_QUERY		# query klmd capabilities
	la	%r1,S390X_KLMD(%r4)
	.long	0xb93f0002		# klmd %r0,%r2

	lghi	%r0,S390X_QUERY		# query km capability vector
	la	%r1,S390X_KM(%r4)
	.long	0xb92e0042		# km %r4,%r2

	lghi	%r0,S390X_QUERY		# query kmc capability vector
	la	%r1,S390X_KMC(%r4)
	.long	0xb92f0042		# kmc %r4,%r2

	lghi	%r0,S390X_QUERY		# query kmac capability vector
	la	%r1,S390X_KMAC(%r4)
	.long	0xb91e0042		# kmac %r4,%r2

	tmhh	%r3,0x0004		# check for message-security-assist-4
	jz	.Lret

	lghi	%r0,S390X_QUERY		# query kmctr capability vector
	la	%r1,S390X_KMCTR(%r4)
	.long	0xb92d2042		# kmctr %r4,%r2,%r2

	lghi	%r0,S390X_QUERY		# query kmo capability vector
	la	%r1,S390X_KMO(%r4)
	.long	0xb92b0042		# kmo %r4,%r2

	lghi	%r0,S390X_QUERY		# query kmf capability vector
	la	%r1,S390X_KMF(%r4)
	.long	0xb92a0042		# kmf %r4,%r2

	tml	%r2,0x40		# check for message-security-assist-5
	jz	.Lret

	lghi	%r0,S390X_QUERY		# query prno capability vector
	la	%r1,S390X_PRNO(%r4)
	.long	0xb93c0042		# prno %r4,%r2

	lg	%r2,S390X_STFLE+16(%r4)
	tmhl	%r2,0x2000		# check for message-security-assist-8
	jz	.Lret

	lghi	%r0,S390X_QUERY		# query kma capability vector
	la	%r1,S390X_KMA(%r4)
	.long	0xb9294022		# kma %r2,%r4,%r2

.Lret:
	br	$ra
.size	OPENSSL_s390x_facilities,.-OPENSSL_s390x_facilities

.globl	OPENSSL_rdtsc
.type	OPENSSL_rdtsc,\@function
.align	16
OPENSSL_rdtsc:
	larl	%r4,OPENSSL_s390xcap_P
	tm	S390X_STFLE+3(%r4),0x40	# check for store-clock-fast facility
	jz	.Lstck

	.long	0xb27cf010	# stckf 16($sp)
	lg	%r2,16($sp)
	br	$ra
.Lstck:
	stck	16($sp)
	lg	%r2,16($sp)
	br	$ra
.size	OPENSSL_rdtsc,.-OPENSSL_rdtsc

.globl	OPENSSL_atomic_add
.type	OPENSSL_atomic_add,\@function
.align	16
OPENSSL_atomic_add:
	l	%r1,0(%r2)
.Lspin:	lr	%r0,%r1
	ar	%r0,%r3
	cs	%r1,%r0,0(%r2)
	brc	4,.Lspin
	lgfr	%r2,%r0		# OpenSSL expects the new value
	br	$ra
.size	OPENSSL_atomic_add,.-OPENSSL_atomic_add

.globl	OPENSSL_wipe_cpu
.type	OPENSSL_wipe_cpu,\@function
.align	16
OPENSSL_wipe_cpu:
	xgr	%r0,%r0
	xgr	%r1,%r1
	lgr	%r2,$sp
	xgr	%r3,%r3
	xgr	%r4,%r4
	lzdr	%f0
	lzdr	%f1
	lzdr	%f2
	lzdr	%f3
	lzdr	%f4
	lzdr	%f5
	lzdr	%f6
	lzdr	%f7
	br	$ra
.size	OPENSSL_wipe_cpu,.-OPENSSL_wipe_cpu

.globl	OPENSSL_cleanse
.type	OPENSSL_cleanse,\@function
.align	16
OPENSSL_cleanse:
#if !defined(__s390x__) && !defined(__s390x)
	llgfr	%r3,%r3
#endif
	lghi	%r4,15
	lghi	%r0,0
	clgr	%r3,%r4
	jh	.Lot
	clgr	%r3,%r0
	bcr	8,%r14
.Little:
	stc	%r0,0(%r2)
	la	%r2,1(%r2)
	brctg	%r3,.Little
	br	%r14
.align	4
.Lot:	tmll	%r2,7
	jz	.Laligned
	stc	%r0,0(%r2)
	la	%r2,1(%r2)
	brctg	%r3,.Lot
.Laligned:
	srlg	%r4,%r3,3
.Loop:	stg	%r0,0(%r2)
	la	%r2,8(%r2)
	brctg	%r4,.Loop
	lghi	%r4,7
	ngr	%r3,%r4
	jnz	.Little
	br	$ra
.size	OPENSSL_cleanse,.-OPENSSL_cleanse

.globl	CRYPTO_memcmp
.type	CRYPTO_memcmp,\@function
.align	16
CRYPTO_memcmp:
#if !defined(__s390x__) && !defined(__s390x)
	llgfr	%r4,%r4
#endif
	lghi	%r5,0
	clgr	%r4,%r5
	je	.Lno_data

.Loop_cmp:
	llgc	%r0,0(%r2)
	la	%r2,1(%r2)
	llgc	%r1,0(%r3)
	la	%r3,1(%r3)
	xr	%r1,%r0
	or	%r5,%r1
	brctg	%r4,.Loop_cmp

	lnr	%r5,%r5
	srl	%r5,31
.Lno_data:
	lgr	%r2,%r5
	br	$ra
.size	CRYPTO_memcmp,.-CRYPTO_memcmp

.globl	OPENSSL_instrument_bus
.type	OPENSSL_instrument_bus,\@function
.align	16
OPENSSL_instrument_bus:
	lghi	%r2,0
	br	%r14
.size	OPENSSL_instrument_bus,.-OPENSSL_instrument_bus

.globl	OPENSSL_instrument_bus2
.type	OPENSSL_instrument_bus2,\@function
.align	16
OPENSSL_instrument_bus2:
	lghi	%r2,0
	br	$ra
.size	OPENSSL_instrument_bus2,.-OPENSSL_instrument_bus2

.globl	OPENSSL_vx_probe
.type	OPENSSL_vx_probe,\@function
.align	16
OPENSSL_vx_probe:
	.word	0xe700,0x0000,0x0044	# vzero %v0
	br	$ra
.size	OPENSSL_vx_probe,.-OPENSSL_vx_probe
___

{
################
# void s390x_kimd(const unsigned char *in, size_t len, unsigned int fc,
#                 void *param)
my ($in,$len,$fc,$param) = map("%r$_",(2..5));
$code.=<<___;
.globl	s390x_kimd
.type	s390x_kimd,\@function
.align	16
s390x_kimd:
	llgfr	%r0,$fc
	lgr	%r1,$param

	.long	0xb93e0002	# kimd %r0,%r2
	brc	1,.-4		# pay attention to "partial completion"

	br	$ra
.size	s390x_kimd,.-s390x_kimd
___
}

{
################
# void s390x_klmd(const unsigned char *in, size_t inlen, unsigned char *out,
#                 size_t outlen, unsigned int fc, void *param)
my ($in,$inlen,$out,$outlen,$fc) = map("%r$_",(2..6));
$code.=<<___;
.globl	s390x_klmd
.type	s390x_klmd,\@function
.align	32
s390x_klmd:
	llgfr	%r0,$fc
	l${g}	%r1,$stdframe($sp)

	.long	0xb93f0042	# klmd %r4,%r2
	brc	1,.-4		# pay attention to "partial completion"

	br	$ra
.size	s390x_klmd,.-s390x_klmd
___
}

################
# void s390x_km(const unsigned char *in, size_t len, unsigned char *out,
#               unsigned int fc, void *param)
{
my ($in,$len,$out,$fc,$param) = map("%r$_",(2..6));
$code.=<<___;
.globl	s390x_km
.type	s390x_km,\@function
.align	16
s390x_km:
	lr	%r0,$fc
	l${g}r	%r1,$param

	.long	0xb92e0042	# km $out,$in
	brc	1,.-4		# pay attention to "partial completion"

	br	$ra
.size	s390x_km,.-s390x_km
___
}

################
# void s390x_kmac(const unsigned char *in, size_t len, unsigned int fc,
#                 void *param)
{
my ($in,$len,$fc,$param) = map("%r$_",(2..5));
$code.=<<___;
.globl	s390x_kmac
.type	s390x_kmac,\@function
.align	16
s390x_kmac:
	lr	%r0,$fc
	l${g}r	%r1,$param

	.long	0xb91e0002	# kmac %r0,$in
	brc	1,.-4		# pay attention to "partial completion"

	br	$ra
.size	s390x_kmac,.-s390x_kmac
___
}

################
# void s390x_kmo(const unsigned char *in, size_t len, unsigned char *out,
#                unsigned int fc, void *param)
{
my ($in,$len,$out,$fc,$param) = map("%r$_",(2..6));
$code.=<<___;
.globl	s390x_kmo
.type	s390x_kmo,\@function
.align	16
s390x_kmo:
	lr	%r0,$fc
	l${g}r	%r1,$param

	.long	0xb92b0042	# kmo $out,$in
	brc	1,.-4		# pay attention to "partial completion"

	br	$ra
.size	s390x_kmo,.-s390x_kmo
___
}

################
# void s390x_kmf(const unsigned char *in, size_t len, unsigned char *out,
#                unsigned int fc, void *param)
{
my ($in,$len,$out,$fc,$param) = map("%r$_",(2..6));
$code.=<<___;
.globl	s390x_kmf
.type	s390x_kmf,\@function
.align	16
s390x_kmf:
	lr	%r0,$fc
	l${g}r	%r1,$param

	.long	0xb92a0042	# kmf $out,$in
	brc	1,.-4		# pay attention to "partial completion"

	br	$ra
.size	s390x_kmf,.-s390x_kmf
___
}

################
# void s390x_kma(const unsigned char *aad, size_t alen,
#                const unsigned char *in, size_t len,
#                unsigned char *out, unsigned int fc, void *param)
{
my ($aad,$alen,$in,$len,$out) = map("%r$_",(2..6));
$code.=<<___;
.globl	s390x_kma
.type	s390x_kma,\@function
.align	16
s390x_kma:
	st${g}	$out,6*$SIZE_T($sp)
	lm${g}	%r0,%r1,$stdframe($sp)

	.long	0xb9292064	# kma $out,$aad,$in
	brc	1,.-4		# pay attention to "partial completion"

	l${g}	$out,6*$SIZE_T($sp)
	br	$ra
.size	s390x_kma,.-s390x_kma
___
}

$code.=<<___;
.section	.init
	brasl	$ra,OPENSSL_cpuid_setup
___

$code =~ s/\`([^\`]*)\`/eval $1/gem;
print $code;
close STDOUT or die "error closing STDOUT: $!";	# force flush


#! /usr/bin/env perl
# Copyright 2004-2020 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

$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
push(@INC, "${dir}perlasm", "perlasm");
require "x86asm.pl";

$output = pop;
open OUT,">$output";
*STDOUT=*OUT;

&asm_init($ARGV[0]);

for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); }

&function_begin("OPENSSL_ia32_cpuid");
	&xor	("edx","edx");
	&pushf	();
	&pop	("eax");
	&mov	("ecx","eax");
	&xor	("eax",1<<21);
	&push	("eax");
	&popf	();
	&pushf	();
	&pop	("eax");
	&xor	("ecx","eax");
	&xor	("eax","eax");
	&mov	("esi",&wparam(0));
	&mov	(&DWP(8,"esi"),"eax");	# clear extended feature flags
	&bt	("ecx",21);
	&jnc	(&label("nocpuid"));
	&cpuid	();
	&mov	("edi","eax");		# max value for standard query level

	&xor	("eax","eax");
	&cmp	("ebx",0x756e6547);	# "Genu"
	&setne	(&LB("eax"));
	&mov	("ebp","eax");
	&cmp	("edx",0x49656e69);	# "ineI"
	&setne	(&LB("eax"));
	&or	("ebp","eax");
	&cmp	("ecx",0x6c65746e);	# "ntel"
	&setne	(&LB("eax"));
	&or	("ebp","eax");		# 0 indicates Intel CPU
	&jz	(&label("intel"));

	&cmp	("ebx",0x68747541);	# "Auth"
	&setne	(&LB("eax"));
	&mov	("esi","eax");
	&cmp	("edx",0x69746E65);	# "enti"
	&setne	(&LB("eax"));
	&or	("esi","eax");
	&cmp	("ecx",0x444D4163);	# "cAMD"
	&setne	(&LB("eax"));
	&or	("esi","eax");		# 0 indicates AMD CPU
	&jnz	(&label("intel"));

	# AMD specific
	&mov	("eax",0x80000000);
	&cpuid	();
	&cmp	("eax",0x80000001);
	&jb	(&label("intel"));
	&mov	("esi","eax");
	&mov	("eax",0x80000001);
	&cpuid	();
	&or	("ebp","ecx");
	&and	("ebp",1<<11|1);	# isolate XOP bit
	&cmp	("esi",0x80000008);
	&jb	(&label("intel"));

	&mov	("eax",0x80000008);
	&cpuid	();
	&movz	("esi",&LB("ecx"));	# number of cores - 1
	&inc	("esi");		# number of cores

	&mov	("eax",1);
	&xor	("ecx","ecx");
	&cpuid	();
	&bt	("edx",28);
	&jnc	(&label("generic"));
	&shr	("ebx",16);
	&and	("ebx",0xff);
	&cmp	("ebx","esi");
	&ja	(&label("generic"));
	&and	("edx",0xefffffff);	# clear hyper-threading bit
	&jmp	(&label("generic"));

&set_label("intel");
	&cmp	("edi",4);
	&mov	("esi",-1);
	&jb	(&label("nocacheinfo"));

	&mov	("eax",4);
	&mov	("ecx",0);		# query L1D
	&cpuid	();
	&mov	("esi","eax");
	&shr	("esi",14);
	&and	("esi",0xfff);		# number of cores -1 per L1D

&set_label("nocacheinfo");
	&mov	("eax",1);
	&xor	("ecx","ecx");
	&cpuid	();
	&and	("edx",0xbfefffff);	# force reserved bits #20, #30 to 0
	&cmp	("ebp",0);
	&jne	(&label("notintel"));
	&or	("edx",1<<30);		# set reserved bit#30 on Intel CPUs
	&and	(&HB("eax"),15);	# family ID
	&cmp	(&HB("eax"),15);	# P4?
	&jne	(&label("notintel"));
	&or	("edx",1<<20);		# set reserved bit#20 to engage RC4_CHAR
&set_label("notintel");
	&bt	("edx",28);		# test hyper-threading bit
	&jnc	(&label("generic"));
	&and	("edx",0xefffffff);
	&cmp	("esi",0);
	&je	(&label("generic"));

	&or	("edx",0x10000000);
	&shr	("ebx",16);
	&cmp	(&LB("ebx"),1);
	&ja	(&label("generic"));
	&and	("edx",0xefffffff);	# clear hyper-threading bit if not

&set_label("generic");
	&and	("ebp",1<<11);		# isolate AMD XOP flag
	&and	("ecx",0xfffff7ff);	# force 11th bit to 0
	&mov	("esi","edx");		# %ebp:%esi is copy of %ecx:%edx
	&or	("ebp","ecx");		# merge AMD XOP flag

	&cmp	("edi",7);
	&mov	("edi",&wparam(0));
	&jb	(&label("no_extended_info"));
	&mov	("eax",7);
	&xor	("ecx","ecx");
	&cpuid	();
	&mov	(&DWP(8,"edi"),"ebx");	# save extended feature flag
&set_label("no_extended_info");

	&bt	("ebp",27);		# check OSXSAVE bit
	&jnc	(&label("clear_avx"));
	&xor	("ecx","ecx");
	&data_byte(0x0f,0x01,0xd0);	# xgetbv
	&and	("eax",6);
	&cmp	("eax",6);
	&je	(&label("done"));
	&cmp	("eax",2);
	&je	(&label("clear_avx"));
&set_label("clear_xmm");
	&and	("ebp",0xfdfffffd);	# clear AESNI and PCLMULQDQ bits
	&and	("esi",0xfeffffff);	# clear FXSR
&set_label("clear_avx");
	&and	("ebp",0xefffe7ff);	# clear AVX, FMA and AMD XOP bits
	&and	(&DWP(8,"edi"),0xffffffdf);	# clear AVX2
&set_label("done");
	&mov	("eax","esi");
	&mov	("edx","ebp");
&set_label("nocpuid");
&function_end("OPENSSL_ia32_cpuid");

&external_label("OPENSSL_ia32cap_P");

&function_begin_B("OPENSSL_rdtsc","EXTRN\t_OPENSSL_ia32cap_P:DWORD");
	&xor	("eax","eax");
	&xor	("edx","edx");
	&picmeup("ecx","OPENSSL_ia32cap_P");
	&bt	(&DWP(0,"ecx"),4);
	&jnc	(&label("notsc"));
	&rdtsc	();
&set_label("notsc");
	&ret	();
&function_end_B("OPENSSL_rdtsc");

# This works in Ring 0 only [read DJGPP+MS-DOS+privileged DPMI host],
# but it's safe to call it on any [supported] 32-bit platform...
# Just check for [non-]zero return value...
&function_begin_B("OPENSSL_instrument_halt","EXTRN\t_OPENSSL_ia32cap_P:DWORD");
	&picmeup("ecx","OPENSSL_ia32cap_P");
	&bt	(&DWP(0,"ecx"),4);
	&jnc	(&label("nohalt"));	# no TSC

	&data_word(0x9058900e);		# push %cs; pop %eax
	&and	("eax",3);
	&jnz	(&label("nohalt"));	# not enough privileges

	&pushf	();
	&pop	("eax");
	&bt	("eax",9);
	&jnc	(&label("nohalt"));	# interrupts are disabled

	&rdtsc	();
	&push	("edx");
	&push	("eax");
	&halt	();
	&rdtsc	();

	&sub	("eax",&DWP(0,"esp"));
	&sbb	("edx",&DWP(4,"esp"));
	&add	("esp",8);
	&ret	();

&set_label("nohalt");
	&xor	("eax","eax");
	&xor	("edx","edx");
	&ret	();
&function_end_B("OPENSSL_instrument_halt");

# Essentially there is only one use for this function. Under DJGPP:
#
#	#include <go32.h>
#	...
#	i=OPENSSL_far_spin(_dos_ds,0x46c);
#	...
# to obtain the number of spins till closest timer interrupt.

&function_begin_B("OPENSSL_far_spin");
	&pushf	();
	&pop	("eax");
	&bt	("eax",9);
	&jnc	(&label("nospin"));	# interrupts are disabled

	&mov	("eax",&DWP(4,"esp"));
	&mov	("ecx",&DWP(8,"esp"));
	&data_word (0x90d88e1e);	# push %ds, mov %eax,%ds
	&xor	("eax","eax");
	&mov	("edx",&DWP(0,"ecx"));
	&jmp	(&label("spin"));

	&align	(16);
&set_label("spin");
	&inc	("eax");
	&cmp	("edx",&DWP(0,"ecx"));
	&je	(&label("spin"));

	&data_word (0x1f909090);	# pop	%ds
	&ret	();

&set_label("nospin");
	&xor	("eax","eax");
	&xor	("edx","edx");
	&ret	();
&function_end_B("OPENSSL_far_spin");

&function_begin_B("OPENSSL_wipe_cpu","EXTRN\t_OPENSSL_ia32cap_P:DWORD");
	&xor	("eax","eax");
	&xor	("edx","edx");
	&picmeup("ecx","OPENSSL_ia32cap_P");
	&mov	("ecx",&DWP(0,"ecx"));
	&bt	(&DWP(0,"ecx"),1);
	&jnc	(&label("no_x87"));
	if ($sse2) {
		&and	("ecx",1<<26|1<<24);	# check SSE2 and FXSR bits
		&cmp	("ecx",1<<26|1<<24);
		&jne	(&label("no_sse2"));
		&pxor	("xmm0","xmm0");
		&pxor	("xmm1","xmm1");
		&pxor	("xmm2","xmm2");
		&pxor	("xmm3","xmm3");
		&pxor	("xmm4","xmm4");
		&pxor	("xmm5","xmm5");
		&pxor	("xmm6","xmm6");
		&pxor	("xmm7","xmm7");
	&set_label("no_sse2");
	}
	# just a bunch of fldz to zap the fp/mm bank followed by finit...
	&data_word(0xeed9eed9,0xeed9eed9,0xeed9eed9,0xeed9eed9,0x90e3db9b);
&set_label("no_x87");
	&lea	("eax",&DWP(4,"esp"));
	&ret	();
&function_end_B("OPENSSL_wipe_cpu");

&function_begin_B("OPENSSL_atomic_add");
	&mov	("edx",&DWP(4,"esp"));	# fetch the pointer, 1st arg
	&mov	("ecx",&DWP(8,"esp"));	# fetch the increment, 2nd arg
	&push	("ebx");
	&nop	();
	&mov	("eax",&DWP(0,"edx"));
&set_label("spin");
	&lea	("ebx",&DWP(0,"eax","ecx"));
	&nop	();
	&data_word(0x1ab10ff0);	# lock;	cmpxchg	%ebx,(%edx)	# %eax is involved and is always reloaded
	&jne	(&label("spin"));
	&mov	("eax","ebx");	# OpenSSL expects the new value
	&pop	("ebx");
	&ret	();
&function_end_B("OPENSSL_atomic_add");

&function_begin_B("OPENSSL_cleanse");
	&mov	("edx",&wparam(0));
	&mov	("ecx",&wparam(1));
	&xor	("eax","eax");
	&cmp	("ecx",7);
	&jae	(&label("lot"));
	&cmp	("ecx",0);
	&je	(&label("ret"));
&set_label("little");
	&mov	(&BP(0,"edx"),"al");
	&sub	("ecx",1);
	&lea	("edx",&DWP(1,"edx"));
	&jnz	(&label("little"));
&set_label("ret");
	&ret	();

&set_label("lot",16);
	&test	("edx",3);
	&jz	(&label("aligned"));
	&mov	(&BP(0,"edx"),"al");
	&lea	("ecx",&DWP(-1,"ecx"));
	&lea	("edx",&DWP(1,"edx"));
	&jmp	(&label("lot"));
&set_label("aligned");
	&mov	(&DWP(0,"edx"),"eax");
	&lea	("ecx",&DWP(-4,"ecx"));
	&test	("ecx",-4);
	&lea	("edx",&DWP(4,"edx"));
	&jnz	(&label("aligned"));
	&cmp	("ecx",0);
	&jne	(&label("little"));
	&ret	();
&function_end_B("OPENSSL_cleanse");

&function_begin_B("CRYPTO_memcmp");
	&push	("esi");
	&push	("edi");
	&mov	("esi",&wparam(0));
	&mov	("edi",&wparam(1));
	&mov	("ecx",&wparam(2));
	&xor	("eax","eax");
	&xor	("edx","edx");
	&cmp	("ecx",0);
	&je	(&label("no_data"));
&set_label("loop");
	&mov	("dl",&BP(0,"esi"));
	&lea	("esi",&DWP(1,"esi"));
	&xor	("dl",&BP(0,"edi"));
	&lea	("edi",&DWP(1,"edi"));
	&or	("al","dl");
	&dec	("ecx");
	&jnz	(&label("loop"));
	&neg	("eax");
	&shr	("eax",31);
&set_label("no_data");
	&pop	("edi");
	&pop	("esi");
	&ret	();
&function_end_B("CRYPTO_memcmp");
{
my $lasttick = "esi";
my $lastdiff = "ebx";
my $out = "edi";
my $cnt = "ecx";
my $max = "ebp";

&function_begin("OPENSSL_instrument_bus");
    &mov	("eax",0);
    if ($sse2) {
	&picmeup("edx","OPENSSL_ia32cap_P");
	&bt	(&DWP(0,"edx"),4);
	&jnc	(&label("nogo"));	# no TSC
	&bt	(&DWP(0,"edx"),19);
	&jnc	(&label("nogo"));	# no CLFLUSH

	&mov	($out,&wparam(0));	# load arguments
	&mov	($cnt,&wparam(1));

	# collect 1st tick
	&rdtsc	();
	&mov	($lasttick,"eax");	# lasttick = tick
	&mov	($lastdiff,0);		# lastdiff = 0
	&clflush(&DWP(0,$out));
	&data_byte(0xf0);		# lock
	&add	(&DWP(0,$out),$lastdiff);
	&jmp	(&label("loop"));

&set_label("loop",16);
	&rdtsc	();
	&mov	("edx","eax");		# put aside tick (yes, I neglect edx)
	&sub	("eax",$lasttick);	# diff
	&mov	($lasttick,"edx");	# lasttick = tick
	&mov	($lastdiff,"eax");	# lastdiff = diff
	&clflush(&DWP(0,$out));
	&data_byte(0xf0);		# lock
	&add	(&DWP(0,$out),"eax");	# accumulate diff
	&lea	($out,&DWP(4,$out));	# ++$out
	&sub	($cnt,1);		# --$cnt
	&jnz	(&label("loop"));

	&mov	("eax",&wparam(1));
&set_label("nogo");
    }
&function_end("OPENSSL_instrument_bus");

&function_begin("OPENSSL_instrument_bus2");
    &mov	("eax",0);
    if ($sse2) {
	&picmeup("edx","OPENSSL_ia32cap_P");
	&bt	(&DWP(0,"edx"),4);
	&jnc	(&label("nogo"));	# no TSC
	&bt	(&DWP(0,"edx"),19);
	&jnc	(&label("nogo"));	# no CLFLUSH

	&mov	($out,&wparam(0));	# load arguments
	&mov	($cnt,&wparam(1));
	&mov	($max,&wparam(2));

	&rdtsc	();			# collect 1st tick
	&mov	($lasttick,"eax");	# lasttick = tick
	&mov	($lastdiff,0);		# lastdiff = 0

	&clflush(&DWP(0,$out));
	&data_byte(0xf0);		# lock
	&add	(&DWP(0,$out),$lastdiff);

	&rdtsc	();			# collect 1st diff
	&mov	("edx","eax");		# put aside tick (yes, I neglect edx)
	&sub	("eax",$lasttick);	# diff
	&mov	($lasttick,"edx");	# lasttick = tick
	&mov	($lastdiff,"eax");	# lastdiff = diff
	&jmp	(&label("loop2"));

&set_label("loop2",16);
	&clflush(&DWP(0,$out));
	&data_byte(0xf0);		# lock
	&add	(&DWP(0,$out),"eax");	# accumulate diff

	&sub	($max,1);
	&jz	(&label("done2"));

	&rdtsc	();
	&mov	("edx","eax");		# put aside tick (yes, I neglect edx)
	&sub	("eax",$lasttick);	# diff
	&mov	($lasttick,"edx");	# lasttick = tick
	&cmp	("eax",$lastdiff);
	&mov	($lastdiff,"eax");	# lastdiff = diff
	&mov	("edx",0);
	&setne	("dl");
	&sub	($cnt,"edx");		# conditional --$cnt
	&lea	($out,&DWP(0,$out,"edx",4));	# conditional ++$out
	&jnz	(&label("loop2"));

&set_label("done2");
	&mov	("eax",&wparam(1));
	&sub	("eax",$cnt);
&set_label("nogo");
    }
&function_end("OPENSSL_instrument_bus2");
}

sub gen_random {
my $rdop = shift;
&function_begin_B("OPENSSL_ia32_${rdop}_bytes");
	&push	("edi");
	&push	("ebx");
	&xor	("eax","eax");		# return value
	&mov	("edi",&wparam(0));
	&mov	("ebx",&wparam(1));

	&cmp	("ebx",0);
	&je	(&label("done"));

	&mov	("ecx",8);
&set_label("loop");
	&${rdop}("edx");
	&jc	(&label("break"));
	&loop	(&label("loop"));
	&jmp	(&label("done"));

&set_label("break",16);
	&cmp	("ebx",4);
	&jb	(&label("tail"));
	&mov	(&DWP(0,"edi"),"edx");
	&lea	("edi",&DWP(4,"edi"));
	&add	("eax",4);
	&sub	("ebx",4);
	&jz	(&label("done"));
	&mov	("ecx",8);
	&jmp	(&label("loop"));

&set_label("tail",16);
	&mov	(&BP(0,"edi"),"dl");
	&lea	("edi",&DWP(1,"edi"));
	&inc	("eax");
	&shr	("edx",8);
	&dec	("ebx");
	&jnz	(&label("tail"));

&set_label("done");
	&xor	("edx","edx");		# Clear random value from registers
	&pop	("ebx");
	&pop	("edi");
	&ret	();
&function_end_B("OPENSSL_ia32_${rdop}_bytes");
}
&gen_random("rdrand");
&gen_random("rdseed");

&initseg("OPENSSL_cpuid_setup");

&hidden("OPENSSL_cpuid_setup");
&hidden("OPENSSL_ia32cap_P");

&asm_finish();

close STDOUT or die "error closing STDOUT: $!";


#! /usr/bin/env perl
# Copyright 2005-2020 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

$flavour = shift;
$output  = shift;
if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }

$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);

$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
( $xlate="${dir}perlasm/x86_64-xlate.pl" and -f $xlate) or
die "can't locate x86_64-xlate.pl";

open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
*STDOUT=*OUT;

($arg1,$arg2,$arg3,$arg4)=$win64?("%rcx","%rdx","%r8", "%r9") :	# Win64 order
				 ("%rdi","%rsi","%rdx","%rcx");	# Unix order

print<<___;
.extern		OPENSSL_cpuid_setup
.hidden		OPENSSL_cpuid_setup
.section	.init
	call	OPENSSL_cpuid_setup

.hidden	OPENSSL_ia32cap_P
.comm	OPENSSL_ia32cap_P,16,4

.text

.globl	OPENSSL_atomic_add
.type	OPENSSL_atomic_add,\@abi-omnipotent
.align	16
OPENSSL_atomic_add:
.cfi_startproc
	movl	($arg1),%eax
.Lspin:	leaq	($arg2,%rax),%r8
	.byte	0xf0		# lock
	cmpxchgl	%r8d,($arg1)
	jne	.Lspin
	movl	%r8d,%eax
	.byte	0x48,0x98	# cltq/cdqe
	ret
.cfi_endproc
.size	OPENSSL_atomic_add,.-OPENSSL_atomic_add

.globl	OPENSSL_rdtsc
.type	OPENSSL_rdtsc,\@abi-omnipotent
.align	16
OPENSSL_rdtsc:
.cfi_startproc
	rdtsc
	shl	\$32,%rdx
	or	%rdx,%rax
	ret
.cfi_endproc
.size	OPENSSL_rdtsc,.-OPENSSL_rdtsc

.globl	OPENSSL_ia32_cpuid
.type	OPENSSL_ia32_cpuid,\@function,1
.align	16
OPENSSL_ia32_cpuid:
.cfi_startproc
	mov	%rbx,%r8		# save %rbx
.cfi_register	%rbx,%r8

	xor	%eax,%eax
	mov	%rax,8(%rdi)		# clear extended feature flags
	cpuid
	mov	%eax,%r11d		# max value for standard query level

	xor	%eax,%eax
	cmp	\$0x756e6547,%ebx	# "Genu"
	setne	%al
	mov	%eax,%r9d
	cmp	\$0x49656e69,%edx	# "ineI"
	setne	%al
	or	%eax,%r9d
	cmp	\$0x6c65746e,%ecx	# "ntel"
	setne	%al
	or	%eax,%r9d		# 0 indicates Intel CPU
	jz	.Lintel

	cmp	\$0x68747541,%ebx	# "Auth"
	setne	%al
	mov	%eax,%r10d
	cmp	\$0x69746E65,%edx	# "enti"
	setne	%al
	or	%eax,%r10d
	cmp	\$0x444D4163,%ecx	# "cAMD"
	setne	%al
	or	%eax,%r10d		# 0 indicates AMD CPU
	jnz	.Lintel

	# AMD specific
	mov	\$0x80000000,%eax
	cpuid
	cmp	\$0x80000001,%eax
	jb	.Lintel
	mov	%eax,%r10d
	mov	\$0x80000001,%eax
	cpuid
	or	%ecx,%r9d
	and	\$0x00000801,%r9d	# isolate AMD XOP bit, 1<<11

	cmp	\$0x80000008,%r10d
	jb	.Lintel

	mov	\$0x80000008,%eax
	cpuid
	movzb	%cl,%r10		# number of cores - 1
	inc	%r10			# number of cores

	mov	\$1,%eax
	cpuid
	bt	\$28,%edx		# test hyper-threading bit
	jnc	.Lgeneric
	shr	\$16,%ebx		# number of logical processors
	cmp	%r10b,%bl
	ja	.Lgeneric
	and	\$0xefffffff,%edx	# ~(1<<28)
	jmp	.Lgeneric

.Lintel:
	cmp	\$4,%r11d
	mov	\$-1,%r10d
	jb	.Lnocacheinfo

	mov	\$4,%eax
	mov	\$0,%ecx		# query L1D
	cpuid
	mov	%eax,%r10d
	shr	\$14,%r10d
	and	\$0xfff,%r10d		# number of cores -1 per L1D

.Lnocacheinfo:
	mov	\$1,%eax
	cpuid
	movd	%eax,%xmm0		# put aside processor id
	and	\$0xbfefffff,%edx	# force reserved bits to 0
	cmp	\$0,%r9d
	jne	.Lnotintel
	or	\$0x40000000,%edx	# set reserved bit#30 on Intel CPUs
	and	\$15,%ah
	cmp	\$15,%ah		# examine Family ID
	jne	.LnotP4
	or	\$0x00100000,%edx	# set reserved bit#20 to engage RC4_CHAR
.LnotP4:
	cmp	\$6,%ah
	jne	.Lnotintel
	and	\$0x0fff0ff0,%eax
	cmp	\$0x00050670,%eax	# Knights Landing
	je	.Lknights
	cmp	\$0x00080650,%eax	# Knights Mill (according to sde)
	jne	.Lnotintel
.Lknights:
	and	\$0xfbffffff,%ecx	# clear XSAVE flag to mimic Silvermont

.Lnotintel:
	bt	\$28,%edx		# test hyper-threading bit
	jnc	.Lgeneric
	and	\$0xefffffff,%edx	# ~(1<<28)
	cmp	\$0,%r10d
	je	.Lgeneric

	or	\$0x10000000,%edx	# 1<<28
	shr	\$16,%ebx
	cmp	\$1,%bl			# see if cache is shared
	ja	.Lgeneric
	and	\$0xefffffff,%edx	# ~(1<<28)
.Lgeneric:
	and	\$0x00000800,%r9d	# isolate AMD XOP flag
	and	\$0xfffff7ff,%ecx
	or	%ecx,%r9d		# merge AMD XOP flag

	mov	%edx,%r10d		# %r9d:%r10d is copy of %ecx:%edx

	cmp	\$7,%r11d
	jb	.Lno_extended_info
	mov	\$7,%eax
	xor	%ecx,%ecx
	cpuid
	bt	\$26,%r9d		# check XSAVE bit, cleared on Knights
	jc	.Lnotknights
	and	\$0xfff7ffff,%ebx	# clear ADCX/ADOX flag
.Lnotknights:
	movd	%xmm0,%eax		# restore processor id
	and	\$0x0fff0ff0,%eax
	cmp	\$0x00050650,%eax	# Skylake-X
	jne	.Lnotskylakex
	and	\$0xfffeffff,%ebx	# ~(1<<16)
					# suppress AVX512F flag on Skylake-X
.Lnotskylakex:
	mov	%ebx,8(%rdi)		# save extended feature flags
	mov	%ecx,12(%rdi)
.Lno_extended_info:

	bt	\$27,%r9d		# check OSXSAVE bit
	jnc	.Lclear_avx
	xor	%ecx,%ecx		# XCR0
	.byte	0x0f,0x01,0xd0		# xgetbv
	and	\$0xe6,%eax		# isolate XMM, YMM and ZMM state support
	cmp	\$0xe6,%eax
	je	.Ldone
	andl	\$0x3fdeffff,8(%rdi)	# ~(1<<31|1<<30|1<<21|1<<16)
					# clear AVX512F+BW+VL+FIMA, all of
					# them are EVEX-encoded, which requires
					# ZMM state support even if one uses
					# only XMM and YMM :-(
	and	\$6,%eax		# isolate XMM and YMM state support
	cmp	\$6,%eax
	je	.Ldone
.Lclear_avx:
	mov	\$0xefffe7ff,%eax	# ~(1<<28|1<<12|1<<11)
	and	%eax,%r9d		# clear AVX, FMA and AMD XOP bits
	mov	\$0x3fdeffdf,%eax	# ~(1<<31|1<<30|1<<21|1<<16|1<<5)
	and	%eax,8(%rdi)		# clear AVX2 and AVX512* bits
.Ldone:
	shl	\$32,%r9
	mov	%r10d,%eax
	mov	%r8,%rbx		# restore %rbx
.cfi_restore	%rbx
	or	%r9,%rax
	ret
.cfi_endproc
.size	OPENSSL_ia32_cpuid,.-OPENSSL_ia32_cpuid

.globl  OPENSSL_cleanse
.type   OPENSSL_cleanse,\@abi-omnipotent
.align  16
OPENSSL_cleanse:
.cfi_startproc
	xor	%rax,%rax
	cmp	\$15,$arg2
	jae	.Lot
	cmp	\$0,$arg2
	je	.Lret
.Little:
	mov	%al,($arg1)
	sub	\$1,$arg2
	lea	1($arg1),$arg1
	jnz	.Little
.Lret:
	ret
.align	16
.Lot:
	test	\$7,$arg1
	jz	.Laligned
	mov	%al,($arg1)
	lea	-1($arg2),$arg2
	lea	1($arg1),$arg1
	jmp	.Lot
.Laligned:
	mov	%rax,($arg1)
	lea	-8($arg2),$arg2
	test	\$-8,$arg2
	lea	8($arg1),$arg1
	jnz	.Laligned
	cmp	\$0,$arg2
	jne	.Little
	ret
.cfi_endproc
.size	OPENSSL_cleanse,.-OPENSSL_cleanse

.globl  CRYPTO_memcmp
.type   CRYPTO_memcmp,\@abi-omnipotent
.align  16
CRYPTO_memcmp:
.cfi_startproc
	xor	%rax,%rax
	xor	%r10,%r10
	cmp	\$0,$arg3
	je	.Lno_data
	cmp	\$16,$arg3
	jne	.Loop_cmp
	mov	($arg1),%r10
	mov	8($arg1),%r11
	mov	\$1,$arg3
	xor	($arg2),%r10
	xor	8($arg2),%r11
	or	%r11,%r10
	cmovnz	$arg3,%rax
	ret

.align	16
.Loop_cmp:
	mov	($arg1),%r10b
	lea	1($arg1),$arg1
	xor	($arg2),%r10b
	lea	1($arg2),$arg2
	or	%r10b,%al
	dec	$arg3
	jnz	.Loop_cmp
	neg	%rax
	shr	\$63,%rax
.Lno_data:
	ret
.cfi_endproc
.size	CRYPTO_memcmp,.-CRYPTO_memcmp
___

print<<___ if (!$win64);
.globl	OPENSSL_wipe_cpu
.type	OPENSSL_wipe_cpu,\@abi-omnipotent
.align	16
OPENSSL_wipe_cpu:
.cfi_startproc
	pxor	%xmm0,%xmm0
	pxor	%xmm1,%xmm1
	pxor	%xmm2,%xmm2
	pxor	%xmm3,%xmm3
	pxor	%xmm4,%xmm4
	pxor	%xmm5,%xmm5
	pxor	%xmm6,%xmm6
	pxor	%xmm7,%xmm7
	pxor	%xmm8,%xmm8
	pxor	%xmm9,%xmm9
	pxor	%xmm10,%xmm10
	pxor	%xmm11,%xmm11
	pxor	%xmm12,%xmm12
	pxor	%xmm13,%xmm13
	pxor	%xmm14,%xmm14
	pxor	%xmm15,%xmm15
	xorq	%rcx,%rcx
	xorq	%rdx,%rdx
	xorq	%rsi,%rsi
	xorq	%rdi,%rdi
	xorq	%r8,%r8
	xorq	%r9,%r9
	xorq	%r10,%r10
	xorq	%r11,%r11
	leaq	8(%rsp),%rax
	ret
.cfi_endproc
.size	OPENSSL_wipe_cpu,.-OPENSSL_wipe_cpu
___
print<<___ if ($win64);
.globl	OPENSSL_wipe_cpu
.type	OPENSSL_wipe_cpu,\@abi-omnipotent
.align	16
OPENSSL_wipe_cpu:
	pxor	%xmm0,%xmm0
	pxor	%xmm1,%xmm1
	pxor	%xmm2,%xmm2
	pxor	%xmm3,%xmm3
	pxor	%xmm4,%xmm4
	pxor	%xmm5,%xmm5
	xorq	%rcx,%rcx
	xorq	%rdx,%rdx
	xorq	%r8,%r8
	xorq	%r9,%r9
	xorq	%r10,%r10
	xorq	%r11,%r11
	leaq	8(%rsp),%rax
	ret
.size	OPENSSL_wipe_cpu,.-OPENSSL_wipe_cpu
___
{
my $out="%r10";
my $cnt="%rcx";
my $max="%r11";
my $lasttick="%r8d";
my $lastdiff="%r9d";
my $redzone=win64?8:-8;

print<<___;
.globl	OPENSSL_instrument_bus
.type	OPENSSL_instrument_bus,\@abi-omnipotent
.align	16
OPENSSL_instrument_bus:
.cfi_startproc
	mov	$arg1,$out	# tribute to Win64
	mov	$arg2,$cnt
	mov	$arg2,$max

	rdtsc			# collect 1st tick
	mov	%eax,$lasttick	# lasttick = tick
	mov	\$0,$lastdiff	# lastdiff = 0
	clflush	($out)
	.byte	0xf0		# lock
	add	$lastdiff,($out)
	jmp	.Loop
.align	16
.Loop:	rdtsc
	mov	%eax,%edx
	sub	$lasttick,%eax
	mov	%edx,$lasttick
	mov	%eax,$lastdiff
	clflush	($out)
	.byte	0xf0		# lock
	add	%eax,($out)
	lea	4($out),$out
	sub	\$1,$cnt
	jnz	.Loop

	mov	$max,%rax
	ret
.cfi_endproc
.size	OPENSSL_instrument_bus,.-OPENSSL_instrument_bus

.globl	OPENSSL_instrument_bus2
.type	OPENSSL_instrument_bus2,\@abi-omnipotent
.align	16
OPENSSL_instrument_bus2:
.cfi_startproc
	mov	$arg1,$out	# tribute to Win64
	mov	$arg2,$cnt
	mov	$arg3,$max
	mov	$cnt,$redzone(%rsp)

	rdtsc			# collect 1st tick
	mov	%eax,$lasttick	# lasttick = tick
	mov	\$0,$lastdiff	# lastdiff = 0

	clflush	($out)
	.byte	0xf0		# lock
	add	$lastdiff,($out)

	rdtsc			# collect 1st diff
	mov	%eax,%edx
	sub	$lasttick,%eax	# diff
	mov	%edx,$lasttick	# lasttick = tick
	mov	%eax,$lastdiff	# lastdiff = diff
.Loop2:
	clflush	($out)
	.byte	0xf0		# lock
	add	%eax,($out)	# accumulate diff

	sub	\$1,$max
	jz	.Ldone2

	rdtsc
	mov	%eax,%edx
	sub	$lasttick,%eax	# diff
	mov	%edx,$lasttick	# lasttick = tick
	cmp	$lastdiff,%eax
	mov	%eax,$lastdiff	# lastdiff = diff
	mov	\$0,%edx
	setne	%dl
	sub	%rdx,$cnt	# conditional --$cnt
	lea	($out,%rdx,4),$out	# conditional ++$out
	jnz	.Loop2

.Ldone2:
	mov	$redzone(%rsp),%rax
	sub	$cnt,%rax
	ret
.cfi_endproc
.size	OPENSSL_instrument_bus2,.-OPENSSL_instrument_bus2
___
}

sub gen_random {
my $rdop = shift;
print<<___;
.globl	OPENSSL_ia32_${rdop}_bytes
.type	OPENSSL_ia32_${rdop}_bytes,\@abi-omnipotent
.align	16
OPENSSL_ia32_${rdop}_bytes:
.cfi_startproc
	xor	%rax, %rax	# return value
	cmp	\$0,$arg2
	je	.Ldone_${rdop}_bytes

	mov	\$8,%r11
.Loop_${rdop}_bytes:
	${rdop}	%r10
	jc	.Lbreak_${rdop}_bytes
	dec	%r11
	jnz	.Loop_${rdop}_bytes
	jmp	.Ldone_${rdop}_bytes

.align	16
.Lbreak_${rdop}_bytes:
	cmp	\$8,$arg2
	jb	.Ltail_${rdop}_bytes
	mov	%r10,($arg1)
	lea	8($arg1),$arg1
	add	\$8,%rax
	sub	\$8,$arg2
	jz	.Ldone_${rdop}_bytes
	mov	\$8,%r11
	jmp	.Loop_${rdop}_bytes

.align	16
.Ltail_${rdop}_bytes:
	mov	%r10b,($arg1)
	lea	1($arg1),$arg1
	inc	%rax
	shr	\$8,%r10
	dec	$arg2
	jnz	.Ltail_${rdop}_bytes

.Ldone_${rdop}_bytes:
	xor	%r10,%r10	# Clear sensitive data from register
	ret
.cfi_endproc
.size	OPENSSL_ia32_${rdop}_bytes,.-OPENSSL_ia32_${rdop}_bytes
___
}
gen_random("rdrand");
gen_random("rdseed");

close STDOUT or die "error closing STDOUT: $!";	# flush