Files
cli/vendor/aws-lc-sys/aws-lc/crypto/fipsmodule/cpucap/cpu_aarch64.c

115 lines
3.5 KiB
C

// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC
#if defined(OPENSSL_AARCH64) && !defined(OPENSSL_STATIC_ARMCAP)
#include "cpu_aarch64.h"
void handle_cpu_env(uint32_t *out, const char *in) {
const int invert = in[0] == '~';
const int or = in[0] == '|';
const int skip_first_byte = invert || or;
const int hex = in[skip_first_byte] == '0' && in[skip_first_byte+1] == 'x';
uint32_t armcap = out[0];
int sscanf_result;
uint32_t v;
if (hex) {
sscanf_result = sscanf(in + skip_first_byte + 2, "%" PRIx32, &v);
} else {
sscanf_result = sscanf(in + skip_first_byte, "%" PRIu32, &v);
}
if (!sscanf_result) {
return;
}
// Detect if the user is trying to use the environment variable to set
// a capability that is _not_ available on the CPU:
// If the runtime capability check (e.g via getauxval() on Linux)
// returned a non-zero hwcap in `armcap` (out)
// and a bit set in the requested `v` is not set in `armcap`,
// abort instead of crashing later.
// The case of invert cannot enable an unexisting capability;
// it can only disable an existing one.
if (!invert && armcap && (~armcap & v))
{
fprintf(stderr,
"Fatal Error: HW capability found: 0x%02X, but HW capability requested: 0x%02X.\n",
armcap, v);
abort();
}
if (invert) {
out[0] &= ~v;
} else if (or) {
out[0] |= v;
} else {
out[0] = v;
}
}
#if defined(AARCH64_DIT_SUPPORTED)
// "DIT" is not recognised as a register name by clang-10 (at least)
// Register's encoded name is from e.g.
// https://github.com/ashwio/arm64-sysreg-lib/blob/d421e249a026f6f14653cb6f9c4edd8c5d898595/include/sysreg/dit.h#L286
#define DIT_REGISTER s3_3_c4_c2_5
DEFINE_STATIC_MUTEX(OPENSSL_armcap_P_lock)
uint64_t armv8_get_dit(void) {
if (CRYPTO_is_ARMv8_DIT_capable()) {
uint64_t val = 0;
__asm__ volatile("mrs %0, s3_3_c4_c2_5" : "=r" (val));
return (val >> 24) & 1;
} else {
return 0;
}
}
// See https://github.com/torvalds/linux/blob/53eaeb7fbe2702520125ae7d72742362c071a1f2/arch/arm64/include/asm/sysreg.h#L82
// As per Arm ARM for v8-A, Section "C.5.1.3 op0 == 0b00, architectural hints,
// barriers and CLREX, and PSTATE access", ARM DDI 0487 J.a, system instructions
// for accessing PSTATE fields have the following encoding
// and C5.2.4 DIT, Data Independent Timing:
// Op0 = 0, CRn = 4
// Op1 (3 for DIT) , Op2 (5 for DIT) encodes the PSTATE field modified and defines the constraints.
// CRm = Imm4 (#0 or #1 below)
// Rt = 0x1f
uint64_t armv8_set_dit(void) {
if (CRYPTO_is_ARMv8_DIT_capable()) {
uint64_t original_dit = armv8_get_dit();
// Encoding of "msr dit, #1"
__asm__ volatile(".inst 0xd503415f");
return original_dit;
} else {
return 0;
}
}
void armv8_restore_dit(volatile uint64_t *original_dit) {
if (*original_dit != 1 && CRYPTO_is_ARMv8_DIT_capable()) {
// Encoding of "msr dit, #0"
__asm__ volatile(".inst 0xd503405f");
}
}
void armv8_disable_dit(void) {
CRYPTO_STATIC_MUTEX_lock_write(OPENSSL_armcap_P_lock_bss_get());
OPENSSL_armcap_P &= ~ARMV8_DIT_ALLOWED;
CRYPTO_STATIC_MUTEX_unlock_write(OPENSSL_armcap_P_lock_bss_get());
}
void armv8_enable_dit(void) {
CRYPTO_STATIC_MUTEX_lock_write(OPENSSL_armcap_P_lock_bss_get());
OPENSSL_armcap_P |= ARMV8_DIT_ALLOWED;
CRYPTO_STATIC_MUTEX_unlock_write(OPENSSL_armcap_P_lock_bss_get());
}
int CRYPTO_is_ARMv8_DIT_capable_for_testing(void) {
return CRYPTO_is_ARMv8_DIT_capable();
}
#endif // AARCH64_DIT_SUPPORTED
#endif // OPENSSL_AARCH64 && !OPENSSL_STATIC_ARMCAP