Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Runtime detection of CPU features #53

Merged
merged 12 commits into from
Apr 30, 2020
18 changes: 0 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,21 +41,3 @@ Unix:
```OCaml
let () = Mirage_crypto_rng_unix.initialize ()
```

#### Illegal instructions

```
Program terminated with signal SIGILL, Illegal instruction.
#0 _mm_aeskeygenassist_si128 (__C=<optimized out>, __X=...)
```

`Mirage_crypto` has CPU acceleration support (`SSE2`+`AES-NI`), but no run-time
autodetection yet. You compiled the library with acceleration, but you are using
it on a machine that does not support it.

The environment variable `MIRAGE_CRYPTO_ACCELERATE` can be used to override
detection:

- `MIRAGE_CRYPTO_ACCELERATE=false dune build` force-disables non-portable code.
- `MIRAGE_CRYPTO_ACCELERATE=true dune build` force-enables non-portable code.
- Otherwise, it matches the capabilities of the build machine.
24 changes: 11 additions & 13 deletions config/cfg.ml
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
let evar = "MIRAGE_CRYPTO_ACCELERATE"
let needs = [`SSSE3; `AES; `PCLMULQDQ]
let flags = ["-DACCELERATE"; "-mssse3"; "-maes"; "-mpclmul"]
let std_flags = ["--std=c99"; "-Wall"; "-Wextra"; "-Wpedantic"; "-O3"]

let _ =
let auto = match Cpuid.supports needs with Ok true -> flags | _ -> [] in
let accelerate_flags = match Sys.getenv evar with
| "true" -> flags
| "false" -> []
| _ -> auto
| exception Not_found -> auto
let c = Configurator.V1.create "mirage-crypto" in
let arch =
let arch = Configurator.V1.Process.run c "uname" ["-m"] in
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just two lines below, the accelerate_flags should be passed -- i.e only on x86 platform, not on arm (this is as far as I can tell what cpuid would have done as well)... or am I misguided and ARM nowadays supports -mssse3 -maes -mpclmul?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was wondering the same. Fixed !
Should it be passed for amd64 and x86 ? It seems only x86_64 was selected in mirage-crypto.h. I removed that check so we have only one place to worry about this.

String.trim arch.Configurator.V1.Process.stdout
in
let accelerate_flags =
match arch with
| "x86_64" | "amd64" -> [ "-DACCELERATE"; "-mssse3"; "-maes"; "-mpclmul" ]
| _ -> []
in
let ent_flags =
let c = Configurator.V1.create "mirage-crypto" in
let arch = Configurator.V1.Process.run c "uname" ["-m"] in
match String.trim arch.Configurator.V1.Process.stdout with
| "x86_64" | "amd64" | "x86" -> [ "-mrdrnd" ; "-mrdseed" ]
match arch with
| "x86_64" | "amd64" | "x86" -> [ "-DENTROPY"; "-mrdrnd"; "-mrdseed" ]
| _ -> []
in
let fs = std_flags @ ent_flags @ accelerate_flags in
Expand Down
2 changes: 1 addition & 1 deletion config/dune
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
(executables
(names cfg)
(libraries dune-configurator cpuid))
(libraries dune-configurator))
3 changes: 0 additions & 3 deletions entropy/mirage_crypto_entropy.ml
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@ module Cpu_native = struct
external unchecked_random : unit -> int = "caml_cpu_unchecked_random" [@@noalloc]
external checked_random : unit -> int = "caml_cpu_checked_random" [@@noalloc]
external rng_type : unit -> int = "caml_cpu_rng_type" [@@noalloc]
external detect : unit -> unit = "caml_entropy_detect"

let () = detect ()

let cpu_rng =
match rng_type () with
Expand Down
1 change: 0 additions & 1 deletion mirage-crypto.opam
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ depends: [
"ocaml" {>= "4.08.0"}
"dune" {>= "1.7"}
"dune-configurator" {>= "2.0.0"}
"cpuid" {build}
"ounit" {with-test}
"cstruct" {>="3.2.0"}
]
Expand Down
3 changes: 2 additions & 1 deletion src/cipher_block.ml
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,7 @@ end

let accelerated =
let flags =
(match Native.misc_mode () with 1 -> [`XOR] | _ -> []) @
(match Native.AES.mode () with 1 -> [`AES] | _ -> []) @
(match Native.GHASH.mode () with 1 -> [`GHASH] | _ -> []) in
match flags with [] -> [] | _ -> `XOR :: flags
flags
4 changes: 2 additions & 2 deletions src/dune
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
(public_name mirage-crypto)
(libraries cstruct)
(private_modules ccm cipher_block cipher_stream hash native uncommon)
(c_names misc
(c_names detect_cpu_features
misc misc_sse
md5 sha1 sha256 sha512 hash_stubs
aes_generic aes_aesni ghash_generic ghash_pclmul
des_generic
Expand All @@ -13,5 +14,4 @@
(include_subdirs unqualified)

(rule
(deps (env_var MIRAGE_CRYPTO_ACCELERATE))
(action (with-stdout-to cflags.sexp (run ../config/cfg.exe))))
9 changes: 9 additions & 0 deletions src/native.ml
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,12 @@ external count16be : bytes -> buffer -> off -> blocks:size -> unit = "mc_count_
external count16be4 : bytes -> buffer -> off -> blocks:size -> unit = "mc_count_16_be_4" [@@noalloc]

external blit : buffer -> off -> buffer -> off -> size -> unit = "caml_blit_bigstring_to_bigstring" [@@noalloc]

external misc_mode : unit -> int = "mc_misc_mode" [@@noalloc]

external _detect_cpu_features : unit -> unit = "mc_detect_cpu_features" [@@noalloc]
external _detect_entropy : unit -> unit = "caml_entropy_detect"

let () =
_detect_cpu_features ();
_detect_entropy ()
63 changes: 40 additions & 23 deletions src/native/aes_aesni.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
*/

#include "mirage_crypto.h"
#if defined (__mc_AES_NI__)
#if defined (__mc_ACCELERATE__)

/* xmm: [3, 2, 1, 0] */
#define _S_3333 0xff
Expand All @@ -23,7 +23,7 @@
*
* XXX Get rid of the correction here.
*/
int _mc_aesni_rk_size (uint8_t rounds) {
static int _mc_aesni_rk_size (uint8_t rounds) {
return (rounds + 1) * 16 + 15;
}

Expand Down Expand Up @@ -336,52 +336,69 @@ static inline void _mc_aesni_dec_blocks (const uint8_t *src, uint8_t *dst, const
__blocked_loop (_mc_aesni_dec, _mc_aesni_dec8, src, dst, rk, rounds, blocks);
}

#endif /* __mc_ACCELERATE__ */

CAMLprim value
mc_aes_rk_size (value rounds) {
return Val_int (_mc_aesni_rk_size (Int_val (rounds)));
value s;
_mc_switch_accel(aesni,
s = mc_aes_rk_size_generic(rounds),
s = Val_int (_mc_aesni_rk_size (Int_val (rounds))))
return s;
}

CAMLprim value
mc_aes_derive_e_key (value key, value off1, value rk, value rounds) {
_mc_aesni_derive_e_key (_ba_uint8_off (key, off1),
_ba_uint8 (rk),
Int_val (rounds));
_mc_switch_accel(aesni,
mc_aes_derive_e_key_generic(key, off1, rk, rounds),
_mc_aesni_derive_e_key (_ba_uint8_off (key, off1),
_ba_uint8 (rk),
Int_val (rounds)))
return Val_unit;
}

CAMLprim value
mc_aes_derive_d_key (value key, value off1, value kr, value rounds, value rk) {
_mc_aesni_derive_d_key (_ba_uint8_off (key, off1),
_ba_uint8 (kr),
Int_val (rounds),
Is_block(rk) ? _ba_uint8(Field(rk, 0)) : 0);
_mc_switch_accel(aesni,
mc_aes_derive_d_key_generic(key, off1, kr, rounds, rk),
_mc_aesni_derive_d_key (_ba_uint8_off (key, off1),
_ba_uint8 (kr),
Int_val (rounds),
Is_block(rk) ? _ba_uint8(Field(rk, 0)) : 0))
return Val_unit;
}

CAMLprim value
mc_aes_enc (value src, value off1, value dst, value off2, value rk, value rounds, value blocks) {
_mc_aesni_enc_blocks ( _ba_uint8_off (src, off1),
_ba_uint8_off (dst, off2),
_ba_uint8 (rk),
Int_val (rounds),
Int_val (blocks) );
_mc_switch_accel(aesni,
mc_aes_enc_generic(src, off1, dst, off2, rk, rounds, blocks),
_mc_aesni_enc_blocks ( _ba_uint8_off (src, off1),
_ba_uint8_off (dst, off2),
_ba_uint8 (rk),
Int_val (rounds),
Int_val (blocks) ))
return Val_unit;
}

CAMLprim value
mc_aes_dec (value src, value off1, value dst, value off2, value rk, value rounds, value blocks) {
_mc_aesni_dec_blocks ( _ba_uint8_off (src, off1),
_ba_uint8_off (dst, off2),
_ba_uint8 (rk),
Int_val (rounds),
Int_val (blocks) );
_mc_switch_accel(aesni,
mc_aes_dec_generic(src, off1, dst, off2, rk, rounds, blocks),
_mc_aesni_dec_blocks ( _ba_uint8_off (src, off1),
_ba_uint8_off (dst, off2),
_ba_uint8 (rk),
Int_val (rounds),
Int_val (blocks) ))
return Val_unit;
}

CAMLprim value mc_aes_mode (__unit ()) { return Val_int (1); }
CAMLprim value mc_aes_mode (__unit ()) {
value enabled = 0;
_mc_switch_accel(aesni,
enabled = 0,
enabled = 1)
return Val_int (enabled);
}

__define_bc_7 (mc_aes_enc)
__define_bc_7 (mc_aes_dec)

#endif /* __mc_AES_NI__ */
19 changes: 5 additions & 14 deletions src/native/aes_generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@

#include "mirage_crypto.h"

#if defined (__mc_AES_GENERIC__)

#define KEYLENGTH(keybits) ((keybits)/8)
#define RKLENGTH(keybits) ((keybits)/8+28)
#define NROUNDS(keybits) ((keybits)/32+6)
Expand Down Expand Up @@ -1229,28 +1227,28 @@ static inline void _mc_aes_dec_blocks (const uint8_t *src, uint8_t *dst, const u
}

CAMLprim value
mc_aes_rk_size (value rounds) {
mc_aes_rk_size_generic (value rounds) {
return Val_int (RKLENGTH (keybits_of_r (Int_val (rounds))) * sizeof(uint32_t));
}

CAMLprim value
mc_aes_derive_e_key (value key, value off1, value rk, value rounds) {
mc_aes_derive_e_key_generic (value key, value off1, value rk, value rounds) {
mc_rijndaelSetupEncrypt (_ba_uint32 (rk),
_ba_uint8_off (key, off1),
keybits_of_r (Int_val (rounds)));
return Val_unit;
}

CAMLprim value
mc_aes_derive_d_key (value key, value off1, value kr, value rounds, value __unused (rk)) {
mc_aes_derive_d_key_generic (value key, value off1, value kr, value rounds, value __unused (rk)) {
mc_rijndaelSetupDecrypt (_ba_uint32 (kr),
_ba_uint8_off (key, off1),
keybits_of_r (Int_val (rounds)));
return Val_unit;
}

CAMLprim value
mc_aes_enc (value src, value off1, value dst, value off2, value rk, value rounds, value blocks) {
mc_aes_enc_generic (value src, value off1, value dst, value off2, value rk, value rounds, value blocks) {
_mc_aes_enc_blocks ( _ba_uint8_off (src, off1),
_ba_uint8_off (dst, off2),
_ba_uint32 (rk),
Expand All @@ -1260,18 +1258,11 @@ mc_aes_enc (value src, value off1, value dst, value off2, value rk, value rounds
}

CAMLprim value
mc_aes_dec (value src, value off1, value dst, value off2, value rk, value rounds, value blocks) {
mc_aes_dec_generic (value src, value off1, value dst, value off2, value rk, value rounds, value blocks) {
_mc_aes_dec_blocks ( _ba_uint8_off (src, off1),
_ba_uint8_off (dst, off2),
_ba_uint32 (rk),
Int_val (rounds),
Int_val (blocks) );
return Val_unit;
}

CAMLprim value mc_aes_mode (__unit ()) { return Val_int (0); }

__define_bc_7 (mc_aes_enc)
__define_bc_7 (mc_aes_dec)

#endif /* __mc_AES_GENERIC__ */
43 changes: 43 additions & 0 deletions src/native/detect_cpu_features.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#include "mirage_crypto.h"

#ifdef __mc_detect_features__

#include <cpuid.h>

struct _mc_cpu_features mc_detected_cpu_features = { 0 };

CAMLprim value
mc_detect_cpu_features (__unit ()) {
unsigned int sig = 0, eax = 0, ebx = 0, ecx = 0, edx = 0;

int max = __get_cpuid_max(0, &sig);

if (max < 1) return Val_unit;

__cpuid(1, eax, ebx, ecx, edx);
if (ecx & bit_PCLMUL)
mc_detected_cpu_features.pclmul = 1;
if (ecx & bit_SSSE3)
mc_detected_cpu_features.ssse3 = 1;
if (ecx & bit_AES)
mc_detected_cpu_features.aesni = 1;
if (ecx & bit_RDRND)
mc_detected_cpu_features.rdrand = 1;

if (max > 7) {
__cpuid_count(7, 0, eax, ebx, ecx, edx);
if (ebx & bit_RDSEED)
mc_detected_cpu_features.rdseed = 1;
}

return Val_unit;
}

#else /* __mc_detect_features__ */

CAMLprim value
mc_detect_cpu_features (__unit ()) {
return Val_unit;
}

#endif /* __mc_detect_features__ */
Loading