diff --git a/crypto/build.info b/crypto/build.info index 8c7a3a9c22..bb5959fb44 100644 --- a/crypto/build.info +++ b/crypto/build.info @@ -51,6 +51,8 @@ IF[{- !$disabled{asm} && $config{processor} ne '386' -}] $CPUIDASM_c64xplus=c64xpluscpuid.s + $CPUIDASM_riscv64=riscvcap.c riscv64cpuid.s + # Now that we have defined all the arch specific variables, use the # appropriate one, and define the appropriate macros IF[$CPUIDASM_{- $target{asm_arch} -}] @@ -130,6 +132,7 @@ GENERATE[armv4cpuid.S]=armv4cpuid.pl INCLUDE[armv4cpuid.o]=. GENERATE[s390xcpuid.S]=s390xcpuid.pl INCLUDE[s390xcpuid.o]=. +GENERATE[riscv64cpuid.s]=riscv64cpuid.pl IF[{- $config{target} =~ /^(?:Cygwin|mingw|VC-|BC-)/ -}] SHARED_SOURCE[../libcrypto]=dllmain.c diff --git a/crypto/riscv64cpuid.pl b/crypto/riscv64cpuid.pl new file mode 100644 index 0000000000..675e9b6111 --- /dev/null +++ b/crypto/riscv64cpuid.pl @@ -0,0 +1,89 @@ +#! /usr/bin/env perl +# Copyright 2022 The OpenSSL Project Authors. All Rights Reserved. +# +# Licensed under the Apache License 2.0 (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 is the last argument if it looks like a file (it has an extension) +# $flavour is the first argument if it doesn't look like a file +$output = $#ARGV >= 0 && $ARGV[$#ARGV] =~ m|\.\w+$| ? pop : undef; +$flavour = $#ARGV >= 0 && $ARGV[0] !~ m|\.| ? shift : undef; + +$output and open STDOUT,">$output"; + +{ +my ($in_a,$in_b,$len,$x,$temp1,$temp2) = ('a0','a1','a2','t0','t1','t2'); +$code.=<<___; +################################################################################ +# int CRYPTO_memcmp(const void * in_a, const void * in_b, size_t len) +################################################################################ +.text +.balign 16 +.globl CRYPTO_memcmp +.type CRYPTO_memcmp,\@function +CRYPTO_memcmp: + li $x,0 + beqz $len,2f # len == 0 +1: + lbu $temp1,0($in_a) + lbu $temp2,0($in_b) + addi $in_a,$in_a,1 + addi $in_b,$in_b,1 + addi $len,$len,-1 + xor $temp1,$temp1,$temp2 + or $x,$x,$temp1 + bgtz $len,1b +2: + mv a0,$x + ret +___ +} +{ +my ($ptr,$len,$temp1,$temp2) = ('a0','a1','t0','t1'); +$code.=<<___; +################################################################################ +# void OPENSSL_cleanse(void *ptr, size_t len) +################################################################################ +.text +.balign 16 +.globl OPENSSL_cleanse +.type OPENSSL_cleanse,\@function +OPENSSL_cleanse: + beqz $len,2f # len == 0, return + srli $temp1,$len,4 + bnez $temp1,3f # len > 15 + +1: # Store <= 15 individual bytes + sb x0,0($ptr) + addi $ptr,$ptr,1 + addi $len,$len,-1 + bnez $len,1b +2: + ret + +3: # Store individual bytes until we are aligned + andi $temp1,$ptr,0x7 + beqz $temp1,4f + sb x0,0($ptr) + addi $ptr,$ptr,1 + addi $len,$len,-1 + j 3b + +4: # Store aligned dwords + li $temp2,8 +4: + sd x0,0($ptr) + addi $ptr,$ptr,8 + addi $len,$len,-8 + bge $len,$temp2,4b # if len>=8 loop + bnez $len,1b # if len<8 and len != 0, store remaining bytes + ret +___ +} + + +print $code; +close STDOUT or die "error closing STDOUT: $!"; diff --git a/crypto/riscvcap.c b/crypto/riscvcap.c new file mode 100644 index 0000000000..1cbfb4a574 --- /dev/null +++ b/crypto/riscvcap.c @@ -0,0 +1,86 @@ +/* + * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (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 + */ + +#include +#include +#include +#include +#include +#include "internal/cryptlib.h" + +#define OPENSSL_RISCVCAP_IMPL +#include "crypto/riscv_arch.h" + +static void parse_env(const char *envstr); +static void strtoupper(char *str); + +uint32_t OPENSSL_rdtsc(void) +{ + return 0; +} + +size_t OPENSSL_instrument_bus(unsigned int *out, size_t cnt) +{ + return 0; +} + +size_t OPENSSL_instrument_bus2(unsigned int *out, size_t cnt, size_t max) +{ + return 0; +} + +static void strtoupper(char *str) +{ + for (char *x = str; *x; ++x) + *x = toupper(*x); +} + +/* parse_env() parses a RISC-V architecture string. An example of such a string + * is "rv64gc_zba_zbb_zbc_zbs". Currently, the rv64gc part is ignored + * and we simply search for "_[extension]" in the arch string to see if we + * should enable a given extension. + */ +#define BUFLEN 256 +static void parse_env(const char *envstr) +{ + char envstrupper[BUFLEN]; + char buf[BUFLEN]; + + /* Convert env str to all uppercase */ + OPENSSL_strlcpy(envstrupper, envstr, sizeof(envstrupper)); + strtoupper(envstrupper); + + for (size_t i = 0; i < kRISCVNumCaps; ++i) { + /* Prefix capability with underscore in preparation for search */ + BIO_snprintf(buf, BUFLEN, "_%s", RISCV_capabilities[i].name); + if (strstr(envstrupper, buf) != NULL) { + /* Match, set relevant bit in OPENSSL_riscvcap_P[] */ + OPENSSL_riscvcap_P[RISCV_capabilities[i].index] |= + (1 << RISCV_capabilities[i].bit_offset); + } + } +} + +# if defined(__GNUC__) && __GNUC__>=2 +__attribute__ ((constructor)) +# endif +void OPENSSL_cpuid_setup(void) +{ + char *e; + static int trigger = 0; + + if (trigger != 0) + return; + trigger = 1; + + if ((e = getenv("OPENSSL_riscvcap"))) { + parse_env(e); + return; + } +} diff --git a/doc/man7/openssl-env.pod b/doc/man7/openssl-env.pod index a2443d54d8..922d3c1476 100644 --- a/doc/man7/openssl-env.pod +++ b/doc/man7/openssl-env.pod @@ -74,7 +74,7 @@ See L. Additional arguments for the L command. -=item B, B, B, B, B +=item B, B, B, B, B, B OpenSSL supports a number of different algorithm implementations for various machines and, by default, it determines which to use based on the @@ -91,7 +91,7 @@ See L. =head1 COPYRIGHT -Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. +Copyright 2019-2022 The OpenSSL Project Authors. All Rights Reserved. Licensed under the Apache License 2.0 (the "License"). You may not use this file except in compliance with the License. You can obtain a copy diff --git a/include/crypto/riscv_arch.def b/include/crypto/riscv_arch.def new file mode 100644 index 0000000000..fb18b1b540 --- /dev/null +++ b/include/crypto/riscv_arch.def @@ -0,0 +1,33 @@ +/* + * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (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 + */ + +/* X Macro Definitions for Specification of RISC-V Arch Capabilities */ + +/* + * Each RISC-V capability ends up encoded as a single set bit in an array of + * words. When specifying a new capability, write a new RISCV_DEFINE_CAP + * statement, with an argument as the extension name in all-caps, + * second argument as the index in the array where the capability will be stored + * and third argument as the index of the bit to be used to encode the + * capability. + * RISCV_DEFINE_CAP(EXTENSION NAME, array index, bit index) */ + +RISCV_DEFINE_CAP(ZBA, 0, 0) +RISCV_DEFINE_CAP(ZBB, 0, 1) +RISCV_DEFINE_CAP(ZBC, 0, 2) +RISCV_DEFINE_CAP(ZBS, 0, 3) + +/* + * In the future ... + * RISCV_DEFINE_CAP(ZFOO, 0, 31) + * RISCV_DEFINE_CAP(ZBAR, 1, 0) + * ... and so on. + */ + +#undef RISCV_DEFINE_CAP diff --git a/include/crypto/riscv_arch.h b/include/crypto/riscv_arch.h new file mode 100644 index 0000000000..89a40bea84 --- /dev/null +++ b/include/crypto/riscv_arch.h @@ -0,0 +1,59 @@ +/* + * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (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 + */ + +#ifndef OSSL_CRYPTO_RISCV_ARCH_H +# define OSSL_CRYPTO_RISCV_ARCH_H + +# include +# include + +# define RISCV_DEFINE_CAP(NAME, INDEX, BIT_INDEX) +1 +extern uint32_t OPENSSL_riscvcap_P[ (( +# include "riscv_arch.def" +) + sizeof(uint32_t) - 1) / sizeof(uint32_t) ]; + +# ifdef OPENSSL_RISCVCAP_IMPL +# define RISCV_DEFINE_CAP(NAME, INDEX, BIT_INDEX) +1 +uint32_t OPENSSL_riscvcap_P[ (( +# include "riscv_arch.def" +) + sizeof(uint32_t) - 1) / sizeof(uint32_t) ]; +# endif + +# define RISCV_DEFINE_CAP(NAME, INDEX, BIT_INDEX) \ + static inline int RISCV_HAS_##NAME(void) \ + { \ + return (OPENSSL_riscvcap_P[INDEX] & (1 << BIT_INDEX)) != 0; \ + } +# include "riscv_arch.def" + +struct RISCV_capability_s { + const char *name; + size_t index; + size_t bit_offset; +}; + +# define RISCV_DEFINE_CAP(NAME, INDEX, BIT_INDEX) +1 +extern const struct RISCV_capability_s RISCV_capabilities[ +# include "riscv_arch.def" +]; + +# ifdef OPENSSL_RISCVCAP_IMPL +# define RISCV_DEFINE_CAP(NAME, INDEX, BIT_INDEX) \ + { #NAME, INDEX, BIT_INDEX }, +const struct RISCV_capability_s RISCV_capabilities[] = { +# include "riscv_arch.def" +}; +# endif + +# define RISCV_DEFINE_CAP(NAME, INDEX, BIT_INDEX) +1 +static const size_t kRISCVNumCaps = +# include "riscv_arch.def" +; + +#endif