1 /* Hardware capability support for run-time dynamic loader.
2    Copyright (C) 2017-2022 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4 
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <https://www.gnu.org/licenses/>.  */
18 
19 #ifndef _DL_HWCAPS_H
20 #define _DL_HWCAPS_H
21 
22 #include <stdint.h>
23 #include <stddef.h>
24 
25 #include <elf/dl-tunables.h>
26 
27 #if HAVE_TUNABLES
28 # define GET_HWCAP_MASK() TUNABLE_GET (glibc, cpu, hwcap_mask, uint64_t, NULL)
29 #else
30 # ifdef SHARED
31 #   define GET_HWCAP_MASK() GLRO(dl_hwcap_mask)
32 # else
33 /* HWCAP_MASK is ignored in static binaries when built without tunables.  */
34 #  define GET_HWCAP_MASK() (0)
35 # endif
36 #endif
37 
38 #define GLIBC_HWCAPS_SUBDIRECTORY "glibc-hwcaps"
39 #define GLIBC_HWCAPS_PREFIX GLIBC_HWCAPS_SUBDIRECTORY "/"
40 
41 /* Used by _dl_hwcaps_split below, to split strings at ':'
42    separators.  */
43 struct dl_hwcaps_split
44 {
45   const char *segment;          /* Start of the current segment.  */
46   size_t length;                /* Number of bytes until ':' or NUL.  */
47 };
48 
49 /* Prepare *S to parse SUBJECT, for future _dl_hwcaps_split calls.  If
50    SUBJECT is NULL, it is treated as the empty string.  */
51 static inline void
_dl_hwcaps_split_init(struct dl_hwcaps_split * s,const char * subject)52 _dl_hwcaps_split_init (struct dl_hwcaps_split *s, const char *subject)
53 {
54   s->segment = subject;
55   /* The initial call to _dl_hwcaps_split will not skip anything.  */
56   s->length = 0;
57 }
58 
59 /* Extract the next non-empty string segment, up to ':' or the null
60    terminator.  Return true if one more segment was found, or false if
61    the end of the string was reached.  On success, S->segment is the
62    start of the segment found, and S->length is its length.
63    (Typically, S->segment[S->length] is not null.)  */
64 _Bool _dl_hwcaps_split (struct dl_hwcaps_split *s) attribute_hidden;
65 
66 /* Similar to dl_hwcaps_split, but with bit-based and name-based
67    masking.  */
68 struct dl_hwcaps_split_masked
69 {
70   struct dl_hwcaps_split split;
71 
72   /* For used by the iterator implementation.  */
73   const char *mask;
74   uint32_t bitmask;
75 };
76 
77 /* Prepare *S for iteration with _dl_hwcaps_split_masked.  Only HWCAP
78    names in SUBJECT whose bit is set in BITMASK and whose name is in
79    MASK will be returned.  SUBJECT must not contain empty HWCAP names.
80    If MASK is NULL, no name-based masking is applied.  Likewise for
81    BITMASK if BITMASK is -1 (infinite number of bits).  */
82 static inline void
_dl_hwcaps_split_masked_init(struct dl_hwcaps_split_masked * s,const char * subject,uint32_t bitmask,const char * mask)83 _dl_hwcaps_split_masked_init (struct dl_hwcaps_split_masked *s,
84                               const char *subject,
85                               uint32_t bitmask, const char *mask)
86 {
87   _dl_hwcaps_split_init (&s->split, subject);
88   s->bitmask = bitmask;
89   s->mask = mask;
90 }
91 
92 /* Like _dl_hwcaps_split, but apply masking.  */
93 _Bool _dl_hwcaps_split_masked (struct dl_hwcaps_split_masked *s)
94   attribute_hidden;
95 
96 /* Returns true if the colon-separated HWCAP list HWCAPS contains the
97    capability NAME (with length NAME_LENGTH).  If HWCAPS is NULL, the
98    function returns true.  */
99 _Bool _dl_hwcaps_contains (const char *hwcaps, const char *name,
100                            size_t name_length) attribute_hidden;
101 
102 /* Colon-separated string of glibc-hwcaps subdirectories, without the
103    "glibc-hwcaps/" prefix.  The most preferred subdirectory needs to
104    be listed first.  Up to 32 subdirectories are supported, limited by
105    the width of the uint32_t mask.  */
106 extern const char _dl_hwcaps_subdirs[] attribute_hidden;
107 
108 /* Returns a bitmap of active subdirectories in _dl_hwcaps_subdirs.
109    Bit 0 (the LSB) corresponds to the first substring in
110    _dl_hwcaps_subdirs, bit 1 to the second substring, and so on.
111    There is no direct correspondence between HWCAP bitmasks and this
112    bitmask.  */
113 uint32_t _dl_hwcaps_subdirs_active (void) attribute_hidden;
114 
115 /* Returns a bitmask that marks the last ACTIVE subdirectories in a
116    _dl_hwcaps_subdirs_active string (containing SUBDIRS directories in
117    total) as active.  Intended for use in _dl_hwcaps_subdirs_active
118    implementations (if a contiguous tail of the list in
119    _dl_hwcaps_subdirs is selected).  */
120 static inline uint32_t
_dl_hwcaps_subdirs_build_bitmask(int subdirs,int active)121 _dl_hwcaps_subdirs_build_bitmask (int subdirs, int active)
122 {
123   /* Leading subdirectories that are not active.  */
124   int inactive = subdirs - active;
125   if (inactive == 32)
126     return 0;
127 
128   uint32_t mask;
129   if (subdirs != 32)
130     mask = (1U << subdirs) - 1;
131   else
132     mask = -1;
133   return mask ^ ((1U << inactive) - 1);
134 }
135 
136 /* Pre-computed glibc-hwcaps subdirectory priorities.  Used in
137    dl-cache.c to quickly find the proprieties for the stored HWCAP
138    names.  */
139 struct dl_hwcaps_priority
140 {
141   /* The name consists of name_length bytes at name (not necessarily
142      null-terminated).  */
143   const char *name;
144   uint32_t name_length;
145 
146   /* Priority of this name.  A positive number.  */
147   uint32_t priority;
148 };
149 
150 /* Pre-computed hwcaps priorities.  Set up by
151    _dl_important_hwcaps.  */
152 extern struct dl_hwcaps_priority *_dl_hwcaps_priorities attribute_hidden;
153 extern uint32_t _dl_hwcaps_priorities_length attribute_hidden;
154 
155 #endif /* _DL_HWCAPS_H */
156