diff options
author | Niels Möller <nisse@lysator.liu.se> | 2015-01-13 10:52:35 +0100 |
---|---|---|
committer | Niels Möller <nisse@lysator.liu.se> | 2015-01-13 10:52:35 +0100 |
commit | aa7ad29333fd8fb3c15fd9022dcd27254f85e8a0 (patch) | |
tree | b9570fa24710802ba8b5b74b5bd2ee564637e550 /x86_64 | |
parent | 23b9cf2215b990314291edcad8c539cae6bfff54 (diff) | |
download | nettle-aa7ad29333fd8fb3c15fd9022dcd27254f85e8a0.tar.gz |
Initial support for fat x86_64 build.
Diffstat (limited to 'x86_64')
-rw-r--r-- | x86_64/fat/aes-decrypt-internal-2.asm | 35 | ||||
-rw-r--r-- | x86_64/fat/aes-decrypt-internal.asm | 35 | ||||
-rw-r--r-- | x86_64/fat/aes-encrypt-internal-2.asm | 35 | ||||
-rw-r--r-- | x86_64/fat/aes-encrypt-internal.asm | 35 | ||||
-rw-r--r-- | x86_64/fat/cpuid.asm | 58 | ||||
-rw-r--r-- | x86_64/fat/fat.c | 229 |
6 files changed, 427 insertions, 0 deletions
diff --git a/x86_64/fat/aes-decrypt-internal-2.asm b/x86_64/fat/aes-decrypt-internal-2.asm new file mode 100644 index 00000000..16fb5598 --- /dev/null +++ b/x86_64/fat/aes-decrypt-internal-2.asm @@ -0,0 +1,35 @@ +C x86_64/fat/aes-decrypt-internal-2.asm + + +ifelse(< + Copyright (C) 2015 Niels Möller + + This file is part of GNU Nettle. + + GNU Nettle is free software: you can redistribute it and/or + modify it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your + option) any later version. + + or both in parallel, as here. + + GNU Nettle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see http://www.gnu.org/licenses/. +>) + +define(<fat_suffix>, <_aesni>) +include_src(<x86_64/aesni/aes-decrypt-internal.asm>) diff --git a/x86_64/fat/aes-decrypt-internal.asm b/x86_64/fat/aes-decrypt-internal.asm new file mode 100644 index 00000000..b05f6a1e --- /dev/null +++ b/x86_64/fat/aes-decrypt-internal.asm @@ -0,0 +1,35 @@ +C x86_64/fat/aes-decrypt-internal.asm + + +ifelse(< + Copyright (C) 2015 Niels Möller + + This file is part of GNU Nettle. + + GNU Nettle is free software: you can redistribute it and/or + modify it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your + option) any later version. + + or both in parallel, as here. + + GNU Nettle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see http://www.gnu.org/licenses/. +>) + +define(<fat_suffix>, <_x86_64>) +include_src(<x86_64/aes-decrypt-internal.asm>) diff --git a/x86_64/fat/aes-encrypt-internal-2.asm b/x86_64/fat/aes-encrypt-internal-2.asm new file mode 100644 index 00000000..c173d0a5 --- /dev/null +++ b/x86_64/fat/aes-encrypt-internal-2.asm @@ -0,0 +1,35 @@ +C x86_64/fat/aes-encrypt-internal-2.asm + + +ifelse(< + Copyright (C) 2015 Niels Möller + + This file is part of GNU Nettle. + + GNU Nettle is free software: you can redistribute it and/or + modify it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your + option) any later version. + + or both in parallel, as here. + + GNU Nettle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see http://www.gnu.org/licenses/. +>) + +define(<fat_suffix>, <_aesni>) +include_src(<x86_64/aesni/aes-encrypt-internal.asm>) diff --git a/x86_64/fat/aes-encrypt-internal.asm b/x86_64/fat/aes-encrypt-internal.asm new file mode 100644 index 00000000..50a721ab --- /dev/null +++ b/x86_64/fat/aes-encrypt-internal.asm @@ -0,0 +1,35 @@ +C x86_64/fat/aes-encrypt-internal.asm + + +ifelse(< + Copyright (C) 2015 Niels Möller + + This file is part of GNU Nettle. + + GNU Nettle is free software: you can redistribute it and/or + modify it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your + option) any later version. + + or both in parallel, as here. + + GNU Nettle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see http://www.gnu.org/licenses/. +>) + +define(<fat_suffix>, <_x86_64>) +include_src(<x86_64/aes-encrypt-internal.asm>) diff --git a/x86_64/fat/cpuid.asm b/x86_64/fat/cpuid.asm new file mode 100644 index 00000000..16a66d57 --- /dev/null +++ b/x86_64/fat/cpuid.asm @@ -0,0 +1,58 @@ +C x86_64/fat/cpuid.asm + +ifelse(< + Copyright (C) 2015 Niels Möller + + This file is part of GNU Nettle. + + GNU Nettle is free software: you can redistribute it and/or + modify it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your + option) any later version. + + or both in parallel, as here. + + GNU Nettle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see http://www.gnu.org/licenses/. +>) + +C Input argument +C cpuid input: %edi +C output pointer: %rsi + + .file "cpuid.asm" + + C void _nettle_cpuid(uint32_t in, uint32_t *out) + + .text + ALIGN(16) +PROLOGUE(_nettle_cpuid) + W64_ENTRY(2) + push %rbx + + movl %edi, %eax + cpuid + mov %eax, (%rsi) + mov %ebx, 4(%rsi) + mov %ecx, 8(%rsi) + mov %edx, 12(%rsi) + + pop %rbx + W64_EXIT(2) + ret +EPILOGUE(_nettle_cpuid) + diff --git a/x86_64/fat/fat.c b/x86_64/fat/fat.c new file mode 100644 index 00000000..3585cf52 --- /dev/null +++ b/x86_64/fat/fat.c @@ -0,0 +1,229 @@ +/* fat.c + + Copyright (C) 2015 Niels Möller + + This file is part of GNU Nettle. + + GNU Nettle is free software: you can redistribute it and/or + modify it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your + option) any later version. + + or both in parallel, as here. + + GNU Nettle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see http://www.gnu.org/licenses/. +*/ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> + +#include "nettle-types.h" + +#include "aes-internal.h" + +/* Fat library initialization works as follows. The main function is + fat_init. It tries to do initialization only once, but since it is + idempotent and pointer updates are atomic on x86_64, there's no + harm if it is in some cases called multiple times from several + threads. + + The fat_init function checks the cpuid flags, and sets function + pointers, e.g, _aes_encrypt_vec, to point to the appropriate + implementation. + + To get everything hooked in, we use a belt-and-suspenders approach. + + When compiling with gcc, we try to register a constructor function + which calls fat_init as soon as the library is loaded. If this is + unavailable or non-working, we instead arrange fat_init to be + called on demand. + + For the actual indirection, there are two cases. + + If ifunc support is available, function pointers are statically + initialized to NULL, and we register resolver functions, e.g., + _aes_encrypt_resolve, which calls fat_init, and then returns the + function pointer, e.g., the value of _aes_encrypt_vec. + + If ifunc is not available, we have to define a wrapper function to + jump via the function pointer. (FIXME: For internal calls, we could + do this as a macro instead). We statically initialize each function + pointer to point to a special initialization function, e.g., + _aes_encrypt_init, which calls fat_init, and then invokes the right + function. This way, all pointers are setup correctly at the first + call to any fat function. +*/ + +#if HAVE_LINK_IFUNC +# define IFUNC(resolve) __attribute__ ((ifunc (resolve))) +#else +# define IFUNC(resolve) +#endif + +void _nettle_cpuid (uint32_t input, uint32_t regs[4]); + +typedef void void_func (void); + +typedef void aes_crypt_internal_func (unsigned rounds, const uint32_t *keys, + const struct aes_table *T, + size_t length, uint8_t *dst, + const uint8_t *src); +aes_crypt_internal_func _aes_encrypt IFUNC ("_aes_encrypt_resolve"); +aes_crypt_internal_func _nettle_aes_encrypt_x86_64; +aes_crypt_internal_func _nettle_aes_encrypt_aesni; + +aes_crypt_internal_func _aes_decrypt IFUNC ("_aes_decrypt_resolve"); +aes_crypt_internal_func _nettle_aes_decrypt_x86_64; +aes_crypt_internal_func _nettle_aes_decrypt_aesni; + +#if HAVE_LINK_IFUNC +#define _aes_encrypt_init NULL +#define _aes_decrypt_init NULL +#else +static aes_crypt_internal_func _aes_encrypt_init; +static aes_crypt_internal_func _aes_decrypt_init; +#endif + +static aes_crypt_internal_func *_aes_encrypt_vec = _aes_encrypt_init; +static aes_crypt_internal_func *_aes_decrypt_vec = _aes_decrypt_init; + +/* This function should usually be called only once, at startup. But + it is idempotent, and on x86, pointer updates are atomic, so + there's no danger if it is called simultaneously from multiple + threads. */ +static void +fat_init (void) +{ + static volatile int initialized = 0; + uint32_t cpuid_data[4]; + int verbose; + if (initialized) + return; + + /* FIXME: Replace all getenv calls by getenv_secure? */ + verbose = getenv ("NETTLE_FAT_VERBOSE") != NULL; + if (verbose) + fprintf (stderr, "libnettle: fat library initialization.\n"); + + _nettle_cpuid (1, cpuid_data); + if (verbose) + fprintf (stderr, "libnettle: cpuid 1: %08x, %08x, %08x, %08x\n", + cpuid_data[0], cpuid_data[1], cpuid_data[2], cpuid_data[3]); + + if (cpuid_data[2] & 0x02000000) + { + if (verbose) + fprintf (stderr, "libnettle: aes instructions available.\n"); + _aes_encrypt_vec = _nettle_aes_encrypt_aesni; + _aes_decrypt_vec = _nettle_aes_decrypt_aesni; + } + else + { + if (verbose) + fprintf (stderr, "libnettle: aes instructions not available.\n"); + _aes_encrypt_vec = _nettle_aes_encrypt_x86_64; + _aes_decrypt_vec = _nettle_aes_decrypt_x86_64; + } + /* FIXME: We ought to use some thread-aware memory barrier before + setting the initialized flag. For now, just do another cpuinfo + call to get some synchronization. */ + _nettle_cpuid (1, cpuid_data); + initialized = 1; +} + +#if __GNUC__ +static void __attribute__ ((constructor)) +fat_constructor (void) +{ + fat_init (); +} +#endif + +#if HAVE_LINK_IFUNC + +static void_func * +_aes_encrypt_resolve (void) +{ + if (getenv ("NETTLE_FAT_VERBOSE")) + fprintf (stderr, "libnettle: _aes_encrypt_resolve\n"); + fat_init (); + return (void_func *) _aes_encrypt_vec; +} + +static void_func * +_aes_decrypt_resolve (void) +{ + if (getenv ("NETTLE_FAT_VERBOSE")) + fprintf (stderr, "libnettle: _aes_decrypt_resolve\n"); + fat_init (); + return (void_func *) _aes_decrypt_vec; +} + +#else /* !HAVE_LINK_IFUNC */ + +/* We need wrapper functions jumping via the function pointer. */ +void +_aes_encrypt (unsigned rounds, const uint32_t *keys, + const struct aes_table *T, + size_t length, uint8_t *dst, + const uint8_t *src) +{ + _aes_encrypt_vec (rounds, keys, T, length, dst, src); +} + +static void +_aes_encrypt_init (unsigned rounds, const uint32_t *keys, + const struct aes_table *T, + size_t length, uint8_t *dst, + const uint8_t *src) +{ + if (getenv ("NETTLE_FAT_VERBOSE")) + fprintf (stderr, "libnettle: _aes_encrypt_init\n"); + fat_init (); + assert (_aes_encrypt_vec != _aes_encrypt_init); + _aes_encrypt (rounds, keys, T, length, dst, src); +} + +void +_aes_decrypt (unsigned rounds, const uint32_t *keys, + const struct aes_table *T, + size_t length, uint8_t *dst, + const uint8_t *src) +{ + _aes_decrypt_vec (rounds, keys, T, length, dst, src); +} + +static void +_aes_decrypt_init (unsigned rounds, const uint32_t *keys, + const struct aes_table *T, + size_t length, uint8_t *dst, + const uint8_t *src) +{ + if (getenv ("NETTLE_FAT_VERBOSE")) + fprintf (stderr, "libnettle: _aes_decrypt_init\n"); + fat_init (); + assert (_aes_decrypt_vec != _aes_decrypt_init); + _aes_decrypt (rounds, keys, T, length, dst, src); +} + +#endif /* !HAVE_LINK_IFUNC */ |