1 /* Processor capability information handling macros.  PowerPC version.
2    Copyright (C) 2005-2021 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_PROCINFO_H
20 #define _DL_PROCINFO_H 1
21 
22 #include <ldsodefs.h>
23 #include <sysdep.h>	/* This defines the PPC_FEATURE[2]_* macros.  */
24 
25 /* The total number of available bits (including those prior to
26    _DL_HWCAP_FIRST).  Some of these bits might not be used.  */
27 #define _DL_HWCAP_COUNT		64
28 
29 /* Features started at bit 31 and decremented as new features were added.  */
30 #define _DL_HWCAP_LAST		31
31 
32 /* AT_HWCAP2 features started at bit 31 and decremented as new features were
33    added.  HWCAP2 feature bits start at bit 0.  */
34 #define _DL_HWCAP2_LAST		31
35 
36 /* These bits influence library search.  */
37 #define HWCAP_IMPORTANT		(PPC_FEATURE_HAS_ALTIVEC \
38 				+ PPC_FEATURE_HAS_DFP)
39 
40 #define _DL_PLATFORMS_COUNT	16
41 
42 #define _DL_FIRST_PLATFORM	32
43 /* Mask to filter out platforms.  */
44 #define _DL_HWCAP_PLATFORM	(((1ULL << _DL_PLATFORMS_COUNT) - 1) \
45 				<< _DL_FIRST_PLATFORM)
46 
47 /* Platform bits (relative to _DL_FIRST_PLATFORM).  */
48 #define PPC_PLATFORM_POWER4		0
49 #define PPC_PLATFORM_PPC970		1
50 #define PPC_PLATFORM_POWER5		2
51 #define PPC_PLATFORM_POWER5_PLUS	3
52 #define PPC_PLATFORM_POWER6		4
53 #define PPC_PLATFORM_CELL_BE		5
54 #define PPC_PLATFORM_POWER6X		6
55 #define PPC_PLATFORM_POWER7		7
56 #define PPC_PLATFORM_PPCA2		8
57 #define PPC_PLATFORM_PPC405		9
58 #define PPC_PLATFORM_PPC440		10
59 #define PPC_PLATFORM_PPC464		11
60 #define PPC_PLATFORM_PPC476		12
61 #define PPC_PLATFORM_POWER8		13
62 #define PPC_PLATFORM_POWER9		14
63 #define PPC_PLATFORM_POWER10		15
64 
65 static inline const char *
66 __attribute__ ((unused))
_dl_hwcap_string(int idx)67 _dl_hwcap_string (int idx)
68 {
69   return GLRO(dl_powerpc_cap_flags)[idx];
70 }
71 
72 static inline int
73 __attribute__ ((unused))
_dl_string_hwcap(const char * str)74 _dl_string_hwcap (const char *str)
75 {
76   for (int i = 0; i < _DL_HWCAP_COUNT; ++i)
77     if (strcmp (str, _dl_hwcap_string (i)) == 0)
78       return i;
79   return -1;
80 }
81 
82 static inline int
83 __attribute__ ((unused, always_inline))
_dl_string_platform(const char * str)84 _dl_string_platform (const char *str)
85 {
86   if (str == NULL)
87     return -1;
88 
89   if (strncmp (str, "power", 5) == 0)
90     {
91       int ret;
92       str += 5;
93       switch (*str)
94 	{
95 	case '1':
96 	  if (str[1] == '0')
97 	    {
98 	      ret = _DL_FIRST_PLATFORM + PPC_PLATFORM_POWER10;
99 	      str++;
100 	    }
101 	  else
102 	    return -1;
103 	  break;
104 	case '4':
105 	  ret = _DL_FIRST_PLATFORM + PPC_PLATFORM_POWER4;
106 	  break;
107 	case '5':
108 	  ret = _DL_FIRST_PLATFORM + PPC_PLATFORM_POWER5;
109 	  if (str[1] == '+')
110 	    {
111 	      ret = _DL_FIRST_PLATFORM + PPC_PLATFORM_POWER5_PLUS;
112 	      ++str;
113 	    }
114 	  break;
115 	case '6':
116 	  ret = _DL_FIRST_PLATFORM + PPC_PLATFORM_POWER6;
117 	  if (str[1] == 'x')
118 	    {
119 	      ret = _DL_FIRST_PLATFORM + PPC_PLATFORM_POWER6X;
120 	      ++str;
121 	    }
122 	  break;
123 	case '7':
124 	  ret = _DL_FIRST_PLATFORM + PPC_PLATFORM_POWER7;
125 	  break;
126 	case '8':
127 	  ret = _DL_FIRST_PLATFORM + PPC_PLATFORM_POWER8;
128 	  break;
129 	case '9':
130 	  ret = _DL_FIRST_PLATFORM + PPC_PLATFORM_POWER9;
131 	  break;
132 	default:
133 	  return -1;
134 	}
135       if (str[1] == '\0')
136        return ret;
137     }
138   else if (strncmp (str, "ppc", 3) == 0)
139     {
140       if (strcmp (str + 3, "970") == 0)
141 	return _DL_FIRST_PLATFORM + PPC_PLATFORM_PPC970;
142       else if (strcmp (str + 3, "-cell-be") == 0)
143 	return _DL_FIRST_PLATFORM + PPC_PLATFORM_CELL_BE;
144       else if (strcmp (str + 3, "a2") == 0)
145 	return _DL_FIRST_PLATFORM + PPC_PLATFORM_PPCA2;
146       else if (strcmp (str + 3, "405") == 0)
147 	return _DL_FIRST_PLATFORM + PPC_PLATFORM_PPC405;
148       else if (strcmp (str + 3, "440") == 0)
149 	return _DL_FIRST_PLATFORM + PPC_PLATFORM_PPC440;
150       else if (strcmp (str + 3, "464") == 0)
151 	return _DL_FIRST_PLATFORM + PPC_PLATFORM_PPC464;
152       else if (strcmp (str + 3, "476") == 0)
153 	return _DL_FIRST_PLATFORM + PPC_PLATFORM_PPC476;
154     }
155 
156   return -1;
157 }
158 
159 #if IS_IN (rtld)
160 static inline void
cache_geometry(const char * name,unsigned long int geometry)161 cache_geometry (const char * name, unsigned long int geometry)
162 {
163   unsigned long int assocty, line;
164 
165   _dl_printf ("%s", name);
166 
167   line = geometry & 0xffff;
168   assocty = (geometry >> 16) & 0xffff;
169 
170   if (line == 0)
171     _dl_printf ("Unknown line size, ");
172   else
173     _dl_printf ("%luB line size, ", line);
174 
175   switch (assocty)
176     {
177     case 0:
178       _dl_printf ("Unknown associativity");
179       break;
180     case 1:
181       _dl_printf ("Directly mapped");
182       break;
183     case 0xffff:
184       _dl_printf ("Fully associative");
185       break;
186     default:
187       _dl_printf ("%lu-way set associative", assocty);
188     }
189 }
190 
191 static inline int
192 __attribute__ ((unused))
_dl_procinfo(unsigned int type,unsigned long int word)193 _dl_procinfo (unsigned int type, unsigned long int word)
194 {
195   switch(type)
196     {
197     case AT_HWCAP:
198       _dl_printf ("AT_HWCAP:            ");
199 
200       for (int i = 0; i <= _DL_HWCAP_LAST; ++i)
201        if (word & (1 << i))
202          _dl_printf (" %s", _dl_hwcap_string (i));
203       break;
204     case AT_HWCAP2:
205       {
206        unsigned int offset = _DL_HWCAP_LAST + 1;
207 
208        _dl_printf ("AT_HWCAP2:           ");
209 
210         /* We have to go through them all because the kernel added the
211           AT_HWCAP2 features starting with the high bits.  */
212        for (int i = 0; i <= _DL_HWCAP2_LAST; ++i)
213          if (word & (1 << i))
214            _dl_printf (" %s", _dl_hwcap_string (offset + i));
215        break;
216       }
217     case AT_L1I_CACHEGEOMETRY:
218       {
219 	cache_geometry ("AT_L1I_CACHEGEOMETRY: ", word);
220 	break;
221       }
222     case AT_L1D_CACHEGEOMETRY:
223       {
224 	cache_geometry ("AT_L1D_CACHEGEOMETRY: ", word);
225 	break;
226       }
227     case AT_L2_CACHEGEOMETRY:
228       {
229 	cache_geometry ("AT_L2_CACHEGEOMETRY:  ", word);
230 	break;
231       }
232     case AT_L3_CACHEGEOMETRY:
233       {
234 	cache_geometry ("AT_L3_CACHEGEOMETRY:  ", word);
235 	break;
236       }
237     default:
238       /* Fallback to generic output mechanism.  */
239       return -1;
240     }
241    _dl_printf ("\n");
242   return 0;
243 }
244 #endif
245 
246 #endif /* dl-procinfo.h */
247