1 /*
2 * Copyright 2022-2024 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10 #include <stdlib.h>
11 #include <string.h>
12 #include <ctype.h>
13 #include <stdint.h>
14 #include <openssl/crypto.h>
15 #include "internal/cryptlib.h"
16
17 #define OPENSSL_RISCVCAP_IMPL
18 #include "crypto/riscv_arch.h"
19
20 #ifdef OSSL_RISCV_HWPROBE
21 # include <unistd.h>
22 # include <sys/syscall.h>
23 # include <asm/hwprobe.h>
24 #endif
25
26 extern size_t riscv_vlen_asm(void);
27
28 static void parse_env(const char *envstr);
29 static void strtoupper(char *str);
30
31 static size_t vlen = 0;
32
OPENSSL_rdtsc(void)33 uint32_t OPENSSL_rdtsc(void)
34 {
35 return 0;
36 }
37
OPENSSL_instrument_bus(unsigned int * out,size_t cnt)38 size_t OPENSSL_instrument_bus(unsigned int *out, size_t cnt)
39 {
40 return 0;
41 }
42
OPENSSL_instrument_bus2(unsigned int * out,size_t cnt,size_t max)43 size_t OPENSSL_instrument_bus2(unsigned int *out, size_t cnt, size_t max)
44 {
45 return 0;
46 }
47
strtoupper(char * str)48 static void strtoupper(char *str)
49 {
50 for (char *x = str; *x; ++x)
51 *x = toupper((unsigned char)*x);
52 }
53
54 /* parse_env() parses a RISC-V architecture string. An example of such a string
55 * is "rv64gc_zba_zbb_zbc_zbs". Currently, the rv64gc part is ignored
56 * and we simply search for "_[extension]" in the arch string to see if we
57 * should enable a given extension.
58 */
59 #define BUFLEN 256
parse_env(const char * envstr)60 static void parse_env(const char *envstr)
61 {
62 char envstrupper[BUFLEN];
63 char buf[BUFLEN];
64
65 /* Convert env str to all uppercase */
66 OPENSSL_strlcpy(envstrupper, envstr, sizeof(envstrupper));
67 strtoupper(envstrupper);
68
69 for (size_t i = 0; i < kRISCVNumCaps; ++i) {
70 /* Prefix capability with underscore in preparation for search */
71 BIO_snprintf(buf, BUFLEN, "_%s", RISCV_capabilities[i].name);
72 if (strstr(envstrupper, buf) != NULL) {
73 /* Match, set relevant bit in OPENSSL_riscvcap_P[] */
74 OPENSSL_riscvcap_P[RISCV_capabilities[i].index] |=
75 (1 << RISCV_capabilities[i].bit_offset);
76 }
77 }
78 }
79
80 #ifdef OSSL_RISCV_HWPROBE
riscv_hwprobe(struct riscv_hwprobe * pairs,size_t pair_count,size_t cpu_count,unsigned long * cpus,unsigned int flags)81 static long riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count,
82 size_t cpu_count, unsigned long *cpus,
83 unsigned int flags)
84 {
85 return syscall(__NR_riscv_hwprobe, pairs, pair_count, cpu_count, cpus, flags);
86 }
87
hwprobe_to_cap(void)88 static void hwprobe_to_cap(void)
89 {
90 long ret;
91 struct riscv_hwprobe pairs[OSSL_RISCV_HWPROBE_PAIR_COUNT] = {
92 OSSL_RISCV_HWPROBE_PAIR_CONTENT
93 };
94
95 ret = riscv_hwprobe(pairs, OSSL_RISCV_HWPROBE_PAIR_COUNT, 0, NULL, 0);
96 /* if hwprobe syscall does not exist, ret would be -ENOSYS */
97 if (ret == 0) {
98 for (size_t i = 0; i < kRISCVNumCaps; ++i) {
99 for (size_t j = 0; j != OSSL_RISCV_HWPROBE_PAIR_COUNT; ++j) {
100 if (pairs[j].key == RISCV_capabilities[i].hwprobe_key
101 && (pairs[j].value & RISCV_capabilities[i].hwprobe_value)
102 != 0)
103 /* Match, set relevant bit in OPENSSL_riscvcap_P[] */
104 OPENSSL_riscvcap_P[RISCV_capabilities[i].index] |=
105 (1 << RISCV_capabilities[i].bit_offset);
106 }
107 }
108 }
109 }
110 #endif /* OSSL_RISCV_HWPROBE */
111
riscv_vlen(void)112 size_t riscv_vlen(void)
113 {
114 return vlen;
115 }
116
117 # if defined(__GNUC__) && __GNUC__>=2
118 __attribute__ ((constructor))
119 # endif
OPENSSL_cpuid_setup(void)120 void OPENSSL_cpuid_setup(void)
121 {
122 char *e;
123 static int trigger = 0;
124
125 if (trigger != 0)
126 return;
127 trigger = 1;
128
129 if ((e = getenv("OPENSSL_riscvcap"))) {
130 parse_env(e);
131 }
132 #ifdef OSSL_RISCV_HWPROBE
133 else {
134 hwprobe_to_cap();
135 }
136 #endif
137
138 if (RISCV_HAS_V()) {
139 vlen = riscv_vlen_asm();
140 }
141 }
142