@@ -33,22 +33,6 @@
# define GLIBC_TUNABLES "GLIBC_TUNABLES"
#endif
-/* Compare environment or tunable names, bounded by the name hardcoded in
- glibc. */
-static bool
-is_name (const char *orig, const char *envname)
-{
- for (;*orig != '\0' && *envname != '\0'; envname++, orig++)
- if (*orig != *envname)
- break;
-
- /* The ENVNAME is immediately followed by a value. */
- if (*orig == '\0' && *envname == '=')
- return true;
- else
- return false;
-}
-
#if TUNABLES_FRONTEND == TUNABLES_FRONTEND_valstring
static char *
tunables_strdup (const char *in)
@@ -235,7 +219,7 @@ parse_tunables (char *tunestr, char *valstring)
{
tunable_t *cur = &tunable_list[i];
- if (is_name (cur->name, name))
+ if (tunable_is_name (cur->name, name))
{
/* If we are in a secure context (AT_SECURE) then ignore the tunable
unless it is explicitly marked as secure. Tunable values take
@@ -318,7 +302,7 @@ __tunables_init (char **envp)
&prev_envp)) != NULL)
{
#if TUNABLES_FRONTEND == TUNABLES_FRONTEND_valstring
- if (is_name (GLIBC_TUNABLES, envname))
+ if (tunable_is_name (GLIBC_TUNABLES, envname))
{
char *new_env = tunables_strdup (envname);
if (new_env != NULL)
@@ -341,7 +325,7 @@ __tunables_init (char **envp)
const char *name = cur->env_alias;
/* We have a match. Initialize and move on to the next line. */
- if (is_name (name, envname))
+ if (tunable_is_name (name, envname))
{
/* For AT_SECURE binaries, we need to check the security settings of
the tunable and decide whether we read the value and also whether
@@ -356,7 +340,7 @@ __tunables_init (char **envp)
while (*ep != NULL)
{
- if (is_name (name, *ep))
+ if (tunable_is_name (name, *ep))
{
char **dp = ep;
@@ -111,5 +111,22 @@ rtld_hidden_proto (__tunable_get_val)
# define TUNABLES_FRONTEND_valstring 1
/* The default value for TUNABLES_FRONTEND. */
# define TUNABLES_FRONTEND_yes TUNABLES_FRONTEND_valstring
+
+/* Compare two name strings, bounded by the name hardcoded in glibc. */
+static inline bool
+__always_inline
+tunable_is_name (const char *orig, const char *envname)
+{
+ for (;*orig != '\0' && *envname != '\0'; envname++, orig++)
+ if (*orig != *envname)
+ break;
+
+ /* The ENVNAME is immediately followed by a value. */
+ if (*orig == '\0' && *envname == '=')
+ return true;
+ else
+ return false;
+}
+
#endif
#endif
@@ -231,6 +231,14 @@ the ones in @code{sysdeps/x86/cpu-features.h}.
This tunable is specific to i386 and x86-64.
@end deftp
+@deftp Tunable glibc.tune.cpu
+The @code{glibc.tune.cpu=xxx} tunable allows the user to tell @theglibc{} to
+assume that the CPU is @code{xxx} where xxx may have one of these values:
+@code{generic}, @code{thunderxt88}.
+
+This tunable is specific to aarch64.
+@end deftp
+
@deftp Tunable glibc.tune.x86_data_cache_size
The @code{glibc.tune.x86_data_cache_size} tunable allows the user to set
data cache size in bytes for use in memory and string routines.
new file mode 100644
@@ -0,0 +1,25 @@
+# aarch64 specific tunables.
+# Copyright (C) 2017 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# The GNU C Library 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
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <http://www.gnu.org/licenses/>.
+
+glibc {
+ tune {
+ cpu {
+ type: STRING
+ }
+ }
+}
@@ -20,18 +20,53 @@
#include <sys/auxv.h>
#include <elf/dl-hwcaps.h>
+#if HAVE_TUNABLES
+struct cpu_list
+{
+ const char *name;
+ uint64_t midr;
+};
+
+static struct cpu_list cpu_list[] = {
+ {"thunderxt88", 0x430F0A10},
+ {"generic", 0x0}
+};
+
+static uint64_t
+get_midr_from_mcpu (const char *mcpu)
+{
+ for (int i = 0; i < sizeof (cpu_list) / sizeof (struct cpu_list); i++)
+ if (tunable_is_name (mcpu, cpu_list[i].name) == 0)
+ return cpu_list[i].midr;
+
+ return UINT64_MAX;
+}
+#endif
+
static inline void
init_cpu_features (struct cpu_features *cpu_features)
{
uint64_t hwcap_mask = GET_HWCAP_MASK();
uint64_t hwcap = GLRO (dl_hwcap) & hwcap_mask;
- if (hwcap & HWCAP_CPUID)
+ register uint64_t midr = UINT64_MAX;
+
+#if HAVE_TUNABLES
+ /* Get the tunable override. */
+ const char *mcpu = TUNABLE_GET (glibc, tune, mcpu, const char *, NULL);
+ if (mcpu != NULL)
+ midr = get_midr_from_mcpu (mcpu);
+#endif
+
+ /* If there was no useful tunable override, query the MIDR if the kernel
+ allows it. */
+ if (midr == UINT64_MAX)
{
- register uint64_t id = 0;
- asm volatile ("mrs %0, midr_el1" : "=r"(id));
- cpu_features->midr_el1 = id;
+ if (hwcap & HWCAP_CPUID)
+ asm volatile ("mrs %0, midr_el1" : "=r"(midr));
+ else
+ midr = 0;
}
- else
- cpu_features->midr_el1 = 0;
+
+ cpu_features->midr_el1 = midr;
}