summaryrefslogtreecommitdiff
path: root/x86_64
diff options
context:
space:
mode:
authorNiels Möller <nisse@lysator.liu.se>2015-01-13 10:52:35 +0100
committerNiels Möller <nisse@lysator.liu.se>2015-01-13 10:52:35 +0100
commitaa7ad29333fd8fb3c15fd9022dcd27254f85e8a0 (patch)
treeb9570fa24710802ba8b5b74b5bd2ee564637e550 /x86_64
parent23b9cf2215b990314291edcad8c539cae6bfff54 (diff)
downloadnettle-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.asm35
-rw-r--r--x86_64/fat/aes-decrypt-internal.asm35
-rw-r--r--x86_64/fat/aes-encrypt-internal-2.asm35
-rw-r--r--x86_64/fat/aes-encrypt-internal.asm35
-rw-r--r--x86_64/fat/cpuid.asm58
-rw-r--r--x86_64/fat/fat.c229
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 */