From 8448432a3be6cd5eb2576594c742e3d54d92f78a Mon Sep 17 00:00:00 2001 From: Henry Brausen Date: Fri, 28 Jan 2022 01:28:52 -0700 Subject: Add basic RISC-V cpuid and OPENSSL_riscvcap RISC-V cpuid implementation allows bitmanip extensions Zb[abcs] to be enabled at runtime using OPENSSL_riscvcap environment variable. For example, to specify 64-bit RISC-V with the G,C,Zba,Zbb,Zbc extensions, one could write: OPENSSL_riscvcap="rv64gc_zba_zbb_zbc" Architecture string parsing is still very primitive, but can be expanded in the future. Currently, only bitmanip extensions Zba, Zbb, Zbc and Zbs are supported. Includes implementation of constant-time CRYPTO_memcmp in riscv64 asm, as well as OPENSSL_cleanse. Assembly implementations are written using perlasm. Reviewed-by: Philipp Tomsich Signed-off-by: Henry Brausen Reviewed-by: Tomas Mraz Reviewed-by: Paul Dale (Merged from https://github.com/openssl/openssl/pull/17640) (cherry picked from commit 360f6dcc5aa1a86ec3ff9a94612b88e3d960ee2e) --- crypto/build.info | 3 ++ crypto/riscv64cpuid.pl | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++ crypto/riscvcap.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 178 insertions(+) create mode 100644 crypto/riscv64cpuid.pl create mode 100644 crypto/riscvcap.c (limited to 'crypto') diff --git a/crypto/build.info b/crypto/build.info index a45bf8deef..f568234081 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; + } +} -- cgit v1.2.3