Skip to content

Commit

Permalink
ppc64le: support OPENSSL_ppccap ENV variable (aws#1569)
Browse files Browse the repository at this point in the history
### Issues:
CryptoAlg-2425

### Description of changes: 
* Architectures for which we have custom assembly implementations need
to provide a mechanism for the environment to alter the CPU capabilities
that are detected at runtime.
* This PR adds support for setting a `OPENSSL_ppccap` environment
variable for this purpose.

### Testing:
* Without setting the environment variable: 55ms
```
[ RUN      ] AESTest.TestVectors
[       OK ] AESTest.TestVectors (55 ms)
```
* After setting `export OPENSSL_ppccap=0x0000000000000000`: 216ms
```
[ RUN      ] AESTest.TestVectors
[       OK ] AESTest.TestVectors (216 ms)
```

By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache 2.0 license and the ISC license.
  • Loading branch information
justsmth authored May 15, 2024
1 parent 7ef93cb commit e89e569
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 8 deletions.
35 changes: 27 additions & 8 deletions crypto/fipsmodule/cpucap/cpu_intel.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,28 +133,47 @@ static void handle_cpu_env(uint32_t *out, const char *in) {
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 intelcap0 = out[0];
uint32_t intelcap1 = out[1];

int sscanf_result;
uint64_t v;
if (hex) {
sscanf_result = sscanf(in + invert + 2, "%" PRIx64, &v);
sscanf_result = sscanf(in + skip_first_byte + 2, "%" PRIx64, &v);
} else {
sscanf_result = sscanf(in + invert, "%" PRIu64, &v);
sscanf_result = sscanf(in + skip_first_byte, "%" PRIu64, &v);
}

if (!sscanf_result) {
return;
}

uint32_t reqcap0 = (uint32_t)(v & UINT32_MAX);
uint32_t reqcap1 = (uint32_t)(v >> 32);

// Detect if the user is trying to use the environment variable to set
// a capability that is _not_ available on the CPU.
// The case of invert cannot enable an unexisting capability;
// it can only disable an existing one.
if (!invert && (intelcap0 || intelcap1)) {
// Allow Intel indicator bit to be set for testing
if((~(1u << 30 | intelcap0) & reqcap0) || (~intelcap1 & reqcap1)) {
fprintf(stderr,
"Fatal Error: HW capability found: 0x%02X 0x%02X, but HW capability requested: 0x%02X 0x%02X.\n",
intelcap0, intelcap1, reqcap0, reqcap1);
abort();
}
}

if (invert) {
out[0] &= ~v;
out[1] &= ~(v >> 32);
out[0] &= ~reqcap0;
out[1] &= ~reqcap1;
} else if (or) {
out[0] |= v;
out[1] |= (v >> 32);
out[0] |= reqcap0;
out[1] |= reqcap1;
} else {
out[0] = v;
out[1] = v >> 32;
out[0] = reqcap0;
out[1] = reqcap1;
}
}

Expand Down
57 changes: 57 additions & 0 deletions crypto/fipsmodule/cpucap/cpu_ppc64le.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,68 @@
#define PPC_FEATURE2_HAS_VCRYPTO 0x02000000
#endif

static void handle_cpu_env(unsigned long *out, const char *in) {
OPENSSL_STATIC_ASSERT(sizeof(unsigned long) == 8, PPC64LE_UNSIGNED_LONG_NOT_8_BYTES);

const int invert = in[0] == '~';
const int or = in[0] == '|';
const int skip_first_byte = (invert || or) ? 1 : 0;
const int hex = in[skip_first_byte] == '0' && in[skip_first_byte+1] == 'x';
unsigned long ppccap = *out;

int sscanf_result;
uint64_t reqcap;
if (hex) {
sscanf_result = sscanf(in + skip_first_byte + 2, "%" PRIx64, &reqcap);
} else {
sscanf_result = sscanf(in + skip_first_byte, "%" PRIu64, &reqcap);
}

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.
// The case of invert cannot enable an unexisting capability;
// it can only disable an existing one.
if (!invert && ppccap && (~ppccap & reqcap)) {
fprintf(stderr,
"Fatal Error: HW capability found: 0x%02lX, but HW capability requested: 0x%02lX.\n",
ppccap, reqcap);
abort();
}

if (invert) {
*out &= ~reqcap;
} else if (or) {
*out |= reqcap;
} else {
*out = reqcap;
}
}

extern uint8_t OPENSSL_cpucap_initialized;

void OPENSSL_cpuid_setup(void) {
OPENSSL_ppc64le_hwcap2 = getauxval(AT_HWCAP2);
OPENSSL_cpucap_initialized = 1;

// OPENSSL_ppccap is a 64-bit hex string which may start with "0x".
// Prior to the value, a '~' or '|' may be given.
//
// If the '~' prefix is present:
// the value is inverted and ANDed with the probed CPUID result
// If the '|' prefix is present:
// the value is ORed with the probed CPUID result
// Otherwise:
// the value is taken as the result of the CPUID
const char *env;
env = getenv("OPENSSL_ppccap");
if (env != NULL) {
handle_cpu_env(&OPENSSL_ppc64le_hwcap2, env);
}

}

int CRYPTO_is_PPC64LE_vcrypto_capable(void) {
Expand Down

0 comments on commit e89e569

Please sign in to comment.