diff options
Diffstat (limited to 'sysdeps')
-rw-r--r-- | sysdeps/generic/dl-tunables-parse.h | 98 | ||||
-rw-r--r-- | sysdeps/s390/cpu-features.c | 47 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/aarch64/cpu-features.c | 38 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/powerpc/cpu-features.c | 49 | ||||
-rw-r--r-- | sysdeps/x86/cpu-tunables.c | 55 |
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 |