about summary refs log tree commit diff
path: root/sysdeps
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps')
-rw-r--r--sysdeps/generic/dl-tunables-parse.h98
-rw-r--r--sysdeps/s390/cpu-features.c47
-rw-r--r--sysdeps/unix/sysv/linux/aarch64/cpu-features.c38
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/cpu-features.c49
-rw-r--r--sysdeps/x86/cpu-tunables.c55
5 files changed, 183 insertions, 104 deletions
diff --git a/sysdeps/generic/dl-tunables-parse.h b/sysdeps/generic/dl-tunables-parse.h
new file mode 100644
index 0000000000..83cecaf416
--- /dev/null
+++ b/sysdeps/generic/dl-tunables-parse.h
@@ -0,0 +1,98 @@
+/* Helper functions to handle tunable strings.
+   Copyright (C) 2023 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
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _DL_TUNABLES_PARSE_H
+#define _DL_TUNABLES_PARSE_H 1
+
+#ifndef DEFAULT_MEMCMP
+# define DEFAULT_MEMCMP memcmp
+#endif
+
+/* Compare the contents of STRVAL with STR of size LEN.  The STR might not
+   be null-terminated.   */
+static inline bool
+tunable_strcmp (const struct tunable_str_t *strval, const char *str,
+		size_t len)
+{
+  return strval->len == len && DEFAULT_MEMCMP (strval->str, str, len) == 0;
+}
+#define tunable_strcmp_cte(__tunable, __str)				\
+ ({									\
+    __builtin_constant_p (__str)					\
+    ? tunable_strcmp (&__tunable->strval, __str, sizeof (__str) - 1)	\
+    : tunable_strcmp (&__tunable->strval, __str, strlen (__str));	\
+ })
+
+/* Helper function to iterate over string tunable composed by multiple
+   suboptions separated by comma.  The tunable is represented as span (address
+   and size) from GLIBC_TUNABLES, so it might not be null terminated.
+
+   For instance, to print all the items:
+
+     struct tunable_str_comma_t st;
+     tunable_str_comma_init (&st, valp);
+
+     struct tunable_str_t tstr;
+     while (tunable_str_comma_next (&st, &tstr))
+      {
+        if (tstr.len == 0)
+	  continue;
+
+	_dl_printf ("[%s] %.*s (%d)\n", __func__,
+		    (int) tstr.len,
+		    tstr.str,
+		    (int) tstr.len);
+      }  */
+
+struct tunable_str_comma_t
+{
+  const char *p;
+  size_t plen;
+  size_t maxplen;
+};
+
+static inline void
+tunable_str_comma_init (struct tunable_str_comma_t *state, tunable_val_t *valp)
+{
+  state->p = valp->strval.str;
+  state->plen = 0;
+  state->maxplen = valp->strval.len;
+}
+
+static inline bool
+tunable_str_comma_next (struct tunable_str_comma_t *state,
+			struct tunable_str_t *str)
+{
+  if (*state->p == '\0' || state->plen >= state->maxplen)
+    return false;
+
+  const char *c;
+  for (c = state->p; *c != ','; c++, state->plen++)
+    if (*c == '\0' || state->plen == state->maxplen)
+      break;
+
+  str->str = state->p;
+  str->len = c - state->p;
+
+  state->p = c + 1;
+  state->plen++;
+
+  return true;
+}
+
+#endif
diff --git a/sysdeps/s390/cpu-features.c b/sysdeps/s390/cpu-features.c
index 39f8c23a60..c1898d8e1e 100644
--- a/sysdeps/s390/cpu-features.c
+++ b/sysdeps/s390/cpu-features.c
@@ -22,6 +22,7 @@
 #include <ifunc-memcmp.h>
 #include <string.h>
 extern __typeof (memcmp) MEMCMP_DEFAULT;
+#include <dl-tunables-parse.h>
 
 #define S390_COPY_CPU_FEATURES(SRC_PTR, DEST_PTR)	\
   (DEST_PTR)->hwcap = (SRC_PTR)->hwcap;			\
@@ -51,32 +52,23 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp)
   struct cpu_features cpu_features_curr;
   S390_COPY_CPU_FEATURES (cpu_features, &cpu_features_curr);
 
-  const char *token = valp->strval;
-  do
+  struct tunable_str_comma_t st;
+  tunable_str_comma_init (&st, valp);
+
+  struct tunable_str_t tstr;
+  while (tunable_str_comma_next (&st, &tstr))
     {
-      const char *token_end, *feature;
-      bool disable;
-      size_t token_len;
-      size_t feature_len;
-
-      /* Find token separator or end of string.  */
-      for (token_end = token; *token_end != ','; token_end++)
-	if (*token_end == '\0')
-	  break;
-
-      /* Determine feature.  */
-      token_len = token_end - token;
-      if (*token == '-')
-	{
-	  disable = true;
-	  feature = token + 1;
-	  feature_len = token_len - 1;
-	}
-      else
+      if (tstr.len == 0)
+	continue;
+
+      const char *feature = tstr.str;
+      size_t feature_len = tstr.len;
+
+      bool disable = *feature == '-';
+      if (disable)
 	{
-	  disable = false;
-	  feature = token;
-	  feature_len = token_len;
+	  feature = feature + 1;
+	  feature_len = feature_len - 1;
 	}
 
       /* Handle only the features here which are really used in the
@@ -187,14 +179,7 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp)
 	  else
 	    cpu_features_curr.stfle_bits[0] |= stfle_bits0_mask;
 	}
-
-      /* Jump over current token ... */
-      token += token_len;
-
-      /* ... and skip token separator for next round.  */
-      if (*token == ',') token++;
     }
-  while (*token != '\0');
 
   /* Copy back the features after checking that no unsupported features were
      enabled by user.  */
diff --git a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c
index dc09c1c827..3f1a6bcd62 100644
--- a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c
+++ b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c
@@ -16,10 +16,12 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
+#include <array_length.h>
 #include <cpu-features.h>
 #include <sys/auxv.h>
 #include <elf/dl-hwcaps.h>
 #include <sys/prctl.h>
+#include <dl-tunables-parse.h>
 
 #define DCZID_DZP_MASK (1 << 4)
 #define DCZID_BS_MASK (0xf)
@@ -33,28 +35,32 @@
 struct cpu_list
 {
   const char *name;
+  size_t len;
   uint64_t midr;
 };
 
-static struct cpu_list cpu_list[] = {
-      {"falkor",	 0x510FC000},
-      {"thunderxt88",	 0x430F0A10},
-      {"thunderx2t99",   0x431F0AF0},
-      {"thunderx2t99p1", 0x420F5160},
-      {"phecda",	 0x680F0000},
-      {"ares",		 0x411FD0C0},
-      {"emag",		 0x503F0001},
-      {"kunpeng920", 	 0x481FD010},
-      {"a64fx",		 0x460F0010},
-      {"generic", 	 0x0}
+static const struct cpu_list cpu_list[] =
+{
+#define CPU_LIST_ENTRY(__str, __num) { __str, sizeof (__str) - 1, __num }
+  CPU_LIST_ENTRY ("falkor",         0x510FC000),
+  CPU_LIST_ENTRY ("thunderxt88",    0x430F0A10),
+  CPU_LIST_ENTRY ("thunderx2t99",   0x431F0AF0),
+  CPU_LIST_ENTRY ("thunderx2t99p1", 0x420F5160),
+  CPU_LIST_ENTRY ("phecda",         0x680F0000),
+  CPU_LIST_ENTRY ("ares",           0x411FD0C0),
+  CPU_LIST_ENTRY ("emag",           0x503F0001),
+  CPU_LIST_ENTRY ("kunpeng920",     0x481FD010),
+  CPU_LIST_ENTRY ("a64fx",          0x460F0010),
+  CPU_LIST_ENTRY ("generic",        0x0),
 };
 
 static uint64_t
-get_midr_from_mcpu (const char *mcpu)
+get_midr_from_mcpu (const struct tunable_str_t *mcpu)
 {
-  for (int i = 0; i < sizeof (cpu_list) / sizeof (struct cpu_list); i++)
-    if (strcmp (mcpu, cpu_list[i].name) == 0)
+  for (int i = 0; i < array_length (cpu_list); i++) {
+    if (tunable_strcmp (mcpu, cpu_list[i].name, cpu_list[i].len))
       return cpu_list[i].midr;
+  }
 
   return UINT64_MAX;
 }
@@ -65,7 +71,9 @@ init_cpu_features (struct cpu_features *cpu_features)
   register uint64_t midr = UINT64_MAX;
 
   /* Get the tunable override.  */
-  const char *mcpu = TUNABLE_GET (glibc, cpu, name, const char *, NULL);
+  const struct tunable_str_t *mcpu = TUNABLE_GET (glibc, cpu, name,
+						  struct tunable_str_t *,
+						  NULL);
   if (mcpu != NULL)
     midr = get_midr_from_mcpu (mcpu);
 
diff --git a/sysdeps/unix/sysv/linux/powerpc/cpu-features.c b/sysdeps/unix/sysv/linux/powerpc/cpu-features.c
index 7c6e20e702..6709213576 100644
--- a/sysdeps/unix/sysv/linux/powerpc/cpu-features.c
+++ b/sysdeps/unix/sysv/linux/powerpc/cpu-features.c
@@ -20,6 +20,7 @@
 #include <stdint.h>
 #include <cpu-features.h>
 #include <elf/dl-tunables.h>
+#include <dl-tunables-parse.h>
 #include <unistd.h>
 #include <string.h>
 
@@ -43,38 +44,33 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp)
   struct cpu_features *cpu_features = &GLRO(dl_powerpc_cpu_features);
   unsigned long int tcbv_hwcap = cpu_features->hwcap;
   unsigned long int tcbv_hwcap2 = cpu_features->hwcap2;
-  const char *token = valp->strval;
-  do
+
+  struct tunable_str_comma_t st;
+  tunable_str_comma_init (&st, valp);
+
+  struct tunable_str_t tstr;
+  while (tunable_str_comma_next (&st, &tstr))
     {
-      const char *token_end, *feature;
-      bool disable;
-      size_t token_len, i, feature_len, offset = 0;
-      /* Find token separator or end of string.  */
-      for (token_end = token; *token_end != ','; token_end++)
-	if (*token_end == '\0')
-	  break;
+      if (tstr.len == 0)
+	continue;
 
-      /* Determine feature.  */
-      token_len = token_end - token;
-      if (*token == '-')
-	{
-	  disable = true;
-	  feature = token + 1;
-	  feature_len = token_len - 1;
-	}
-      else
+      const char *feature = tstr.str;
+      size_t feature_len = tstr.len;
+
+      bool disable = *feature == '-';
+      if (disable)
 	{
-	  disable = false;
-	  feature = token;
-	  feature_len = token_len;
+	  feature = feature + 1;
+	  feature_len = feature_len - 1;
 	}
-      for (i = 0; i < array_length (hwcap_tunables); ++i)
+
+      size_t offset = 0;
+      for (int i = 0; i < array_length (hwcap_tunables); ++i)
 	{
 	  const char *hwcap_name = hwcap_names + offset;
 	  size_t hwcap_name_len = strlen (hwcap_name);
 	  /* Check the tunable name on the supported list.  */
-	  if (hwcap_name_len == feature_len
-	      && memcmp (feature, hwcap_name, feature_len) == 0)
+	  if (tunable_strcmp (&tstr, hwcap_name, hwcap_name_len))
 	    {
 	      /* Update the hwcap and hwcap2 bits.  */
 	      if (disable)
@@ -98,12 +94,7 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp)
 	    }
 	  offset += hwcap_name_len + 1;
 	}
-	token += token_len;
-	/* ... and skip token separator for next round.  */
-	if (*token == ',')
-	  token++;
     }
-  while (*token != '\0');
 }
 
 static inline void
diff --git a/sysdeps/x86/cpu-tunables.c b/sysdeps/x86/cpu-tunables.c
index 0d4f328585..48e6a865a1 100644
--- a/sysdeps/x86/cpu-tunables.c
+++ b/sysdeps/x86/cpu-tunables.c
@@ -38,6 +38,7 @@ extern __typeof (memcmp) DEFAULT_MEMCMP;
 #else
 # define DEFAULT_MEMCMP	memcmp
 #endif
+#include <dl-tunables-parse.h>
 
 #define CHECK_GLIBC_IFUNC_CPU_OFF(f, cpu_features, name, len)		\
   _Static_assert (sizeof (#name) - 1 == len, #name " != " #len);	\
@@ -106,33 +107,33 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp)
      NOTE: the IFUNC selection may change over time.  Please check all
      multiarch implementations when experimenting.  */
 
-  const char *p = valp->strval, *c;
   struct cpu_features *cpu_features = &GLRO(dl_x86_cpu_features);
-  size_t len;
 
-  do
+  struct tunable_str_comma_t st;
+  tunable_str_comma_init (&st, valp);
+
+  struct tunable_str_t tstr;
+  while (tunable_str_comma_next (&st, &tstr))
     {
-      const char *n;
-      bool disable;
-      size_t nl;
+      if (tstr.len == 0)
+	continue;
 
-      for (c = p; *c != ','; c++)
-	if (*c == '\0')
-	  break;
+      const char *n = tstr.str;
+      size_t len = tstr.len;
 
-      len = c - p;
-      disable = *p == '-';
+      bool disable = *n == '-';
       if (disable)
 	{
-	  n = p + 1;
-	  nl = len - 1;
-	}
-      else
-	{
-	  n = p;
-	  nl = len;
+	  n = n + 1;
+	  len = len - 1;
 	}
-      switch (nl)
+
+	_dl_printf ("[%s] %.*s (%d)\n", __func__,
+		    (int) tstr.len,
+		    tstr.str,
+		    (int) tstr.len);
+
+      switch (len)
 	{
 	default:
 	  break;
@@ -280,9 +281,7 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp)
 	    }
 	  break;
 	}
-      p += len + 1;
     }
-  while (*c != '\0');
 }
 
 #if CET_ENABLED
@@ -290,12 +289,11 @@ attribute_hidden
 void
 TUNABLE_CALLBACK (set_x86_ibt) (tunable_val_t *valp)
 {
-  if (DEFAULT_MEMCMP (valp->strval, "on", sizeof ("on")) == 0)
+  if (tunable_strcmp_cte (valp, "on"))
     GL(dl_x86_feature_control).ibt = cet_always_on;
-  else if (DEFAULT_MEMCMP (valp->strval, "off", sizeof ("off")) == 0)
+  else if (tunable_strcmp_cte (valp, "off"))
     GL(dl_x86_feature_control).ibt = cet_always_off;
-  else if (DEFAULT_MEMCMP (valp->strval, "permissive",
-			   sizeof ("permissive")) == 0)
+  else if (tunable_strcmp_cte (valp, "permissive"))
     GL(dl_x86_feature_control).ibt = cet_permissive;
 }
 
@@ -303,12 +301,11 @@ attribute_hidden
 void
 TUNABLE_CALLBACK (set_x86_shstk) (tunable_val_t *valp)
 {
-  if (DEFAULT_MEMCMP (valp->strval, "on", sizeof ("on")) == 0)
+  if (tunable_strcmp_cte (valp, "on"))
     GL(dl_x86_feature_control).shstk = cet_always_on;
-  else if (DEFAULT_MEMCMP (valp->strval, "off", sizeof ("off")) == 0)
+  else if (tunable_strcmp_cte (valp, "off"))
     GL(dl_x86_feature_control).shstk = cet_always_off;
-  else if (DEFAULT_MEMCMP (valp->strval, "permissive",
-			   sizeof ("permissive")) == 0)
+  else if (tunable_strcmp_cte (valp, "permissive"))
     GL(dl_x86_feature_control).shstk = cet_permissive;
 }
 #endif