#ifndef OPENSSL_HEADER_CRYPTO_CPU_ARM_LINUX_H
#define OPENSSL_HEADER_CRYPTO_CPU_ARM_LINUX_H
#include <openssl/base.h>
#include <string.h>
#include "internal.h"
#if defined(__cplusplus)
extern "C" {
#endif
#define HWCAP_NEON (1 << 12)
#define HWCAP2_AES (1 << 0)
#define HWCAP2_PMULL (1 << 1)
#define HWCAP2_SHA1 (1 << 2)
#define HWCAP2_SHA2 (1 << 3)
typedef struct {
const char *data;
size_t len;
} STRING_PIECE;
static int STRING_PIECE_equals(const STRING_PIECE *a, const char *b) {
size_t b_len = strlen(b);
return a->len == b_len && OPENSSL_memcmp(a->data, b, b_len) == 0;
}
static int STRING_PIECE_split(STRING_PIECE *out_left, STRING_PIECE *out_right,
const STRING_PIECE *in, char sep) {
const char *p = (const char *)OPENSSL_memchr(in->data, sep, in->len);
if (p == NULL) {
return 0;
}
STRING_PIECE in_copy = *in;
out_left->data = in_copy.data;
out_left->len = p - in_copy.data;
out_right->data = in_copy.data + out_left->len + 1;
out_right->len = in_copy.len - out_left->len - 1;
return 1;
}
static int STRING_PIECE_get_delimited(STRING_PIECE *s, STRING_PIECE *out, char sep) {
if (s->len == 0) {
return 0;
}
if (!STRING_PIECE_split(out, s, s, sep)) {
*out = *s;
s->data += s->len;
s->len = 0;
}
return 1;
}
static void STRING_PIECE_trim(STRING_PIECE *s) {
while (s->len != 0 && (s->data[0] == ' ' || s->data[0] == '\t')) {
s->data++;
s->len--;
}
while (s->len != 0 &&
(s->data[s->len - 1] == ' ' || s->data[s->len - 1] == '\t')) {
s->len--;
}
}
static int extract_cpuinfo_field(STRING_PIECE *out, const STRING_PIECE *in,
const char *field) {
STRING_PIECE remaining = *in, line;
while (STRING_PIECE_get_delimited(&remaining, &line, '\n')) {
STRING_PIECE key, value;
if (!STRING_PIECE_split(&key, &value, &line, ':')) {
continue;
}
STRING_PIECE_trim(&key);
if (STRING_PIECE_equals(&key, field)) {
STRING_PIECE_trim(&value);
*out = value;
return 1;
}
}
return 0;
}
static int cpuinfo_field_equals(const STRING_PIECE *cpuinfo, const char *field,
const char *value) {
STRING_PIECE extracted;
return extract_cpuinfo_field(&extracted, cpuinfo, field) &&
STRING_PIECE_equals(&extracted, value);
}
static int has_list_item(const STRING_PIECE *list, const char *item) {
STRING_PIECE remaining = *list, feature;
while (STRING_PIECE_get_delimited(&remaining, &feature, ' ')) {
if (STRING_PIECE_equals(&feature, item)) {
return 1;
}
}
return 0;
}
static unsigned long crypto_get_arm_hwcap_from_cpuinfo(
const STRING_PIECE *cpuinfo) {
if (cpuinfo_field_equals(cpuinfo, "CPU architecture", "8")) {
return HWCAP_NEON;
}
STRING_PIECE features;
if (extract_cpuinfo_field(&features, cpuinfo, "Features") &&
has_list_item(&features, "neon")) {
return HWCAP_NEON;
}
return 0;
}
static unsigned long crypto_get_arm_hwcap2_from_cpuinfo(
const STRING_PIECE *cpuinfo) {
STRING_PIECE features;
if (!extract_cpuinfo_field(&features, cpuinfo, "Features")) {
return 0;
}
unsigned long ret = 0;
if (has_list_item(&features, "aes")) {
ret |= HWCAP2_AES;
}
if (has_list_item(&features, "pmull")) {
ret |= HWCAP2_PMULL;
}
if (has_list_item(&features, "sha1")) {
ret |= HWCAP2_SHA1;
}
if (has_list_item(&features, "sha2")) {
ret |= HWCAP2_SHA2;
}
return ret;
}
static int crypto_cpuinfo_has_broken_neon(const STRING_PIECE *cpuinfo) {
return cpuinfo_field_equals(cpuinfo, "CPU implementer", "0x51") &&
cpuinfo_field_equals(cpuinfo, "CPU architecture", "7") &&
cpuinfo_field_equals(cpuinfo, "CPU variant", "0x1") &&
cpuinfo_field_equals(cpuinfo, "CPU part", "0x04d") &&
cpuinfo_field_equals(cpuinfo, "CPU revision", "0");
}
#if defined(__cplusplus)
} #endif
#endif