mc-manual.xml fix new/delete expresions -> expression
[valgrind.git] / tests / s390x_features.c
blob507f3ab2f8ce6cc6cbfafa955095f42a0cad0e74
1 /* -*- mode: C; c-basic-offset: 3; -*- */
3 #include <setjmp.h>
4 #include <signal.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <assert.h>
9 #include <ctype.h> // isspace
10 #include <fcntl.h> // open
11 #include <unistd.h> // lseek
12 #include <sys/stat.h> // S_IRUSR
14 // <features.h> is a glibc-specific extension, other libc's may not provide it
15 #ifdef __GLIBC__
16 #include <features.h> // __GLIBC_PREREQ
17 #endif
19 // This file determines s390x features a processor supports.
21 // We return:
22 // - 0 if the machine provides the asked-for feature and the cpu
23 // model, if specified, matches the machine
24 // - 1 the machine does not provide the asked-for feature or the
25 // cpu model, if specified, does not match the machine
26 // - 1 for an unknown cpu model in /proc/cpu_info
27 // - 2 if the asked-for feature isn't recognised (this will be the case for
28 // any feature if run on a non-s390x machine).
29 // - 3 if there was a usage error (it also prints an error message).
31 // USAGE:
33 // s390x_features <feature> [<machine-model>]
35 // The machine_model is optional and it can be something like:
37 // z9 -- Host needs to be a z9 (and nothing else)
38 // z9: -- Host needs to be a z9 or any later model
39 // :z9 -- Host needs to be a model up to and including z9
40 // z900:z9 -- Host needs to be at least a z900 and at most a z9.
41 // Any model in between is OK, too.
43 jmp_buf env;
45 #if defined(VGA_s390x)
47 // Features that require kernel support should be checked against HWCAP instead
48 // of the CPU facility list. To read the HWCAP, use 'getauxval' if available --
49 // which should be the case with glibc versions >= 2.16. A system with an older
50 // glibc is unlikely to support any of these features anyhow.
51 #if __GLIBC_PREREQ(2, 16)
52 #include <sys/auxv.h>
53 #define GET_HWCAP() getauxval(AT_HWCAP)
54 #else
55 #define GET_HWCAP() 0UL
56 #endif
58 /* Number of double words needed to store all facility bits. */
59 #define S390_NUM_FACILITY_DW 3
61 void handle_sigill(int signum)
63 longjmp(env, 1);
66 static void clear_facilities(unsigned long long *ret)
68 unsigned int index;
69 for(index = 0; index < S390_NUM_FACILITY_DW; index++)
71 ret[index] = 0ULL;
75 void stfle(unsigned long long *ret)
77 signal(SIGILL, handle_sigill);
78 if (setjmp(env)) {
79 /* stfle not available: assume no facilities */
80 clear_facilities(ret);
81 } else {
82 register unsigned long long r0 asm("0") = S390_NUM_FACILITY_DW - 1;
83 asm volatile(".insn s,0xb2b00000,%0\n" /* stfle */
84 : "=m" (*ret), "+d"(r0) :: "cc", "memory");
89 /* Read /proc/cpuinfo. Look for lines like these
91 processor 0: version = FF, identification = 0117C9, machine = 2064
93 and return the machine model or NULL on error.
94 Adapted from function VG_(get_machine_model) in coregrind/m_machine.c */
96 typedef struct {
97 const char *cpuinfo_name;
98 const char *real_name;
99 } model_info;
101 /* Array needs to be sorted chronologically. Oldest to newest */
102 model_info models[] = {
103 { "2064", "z900" },
104 { "2066", "z800" },
105 { "2084", "z990" },
106 { "2086", "z890" },
107 { "2094", "z9-EC" },
108 { "2096", "z9-BC" },
109 { "2097", "z10-EC" },
110 { "2098", "z10-BC" },
111 { "2817", "z196" },
112 { "2818", "z114" },
113 { "2827", "zEC12" },
114 { "2828", "zBC12" },
115 { "2964", "z13" },
116 { "2965", "z13s" },
117 { "3906", "z14" },
118 { "3907", "z14 ZR1"},
119 { "8561", "z15" },
120 { "8562", "z15" },
121 { "3931", "z16" },
122 { "3932", "z16" },
126 /* Locate a machine model by name. Name can be either the cpuinfo
127 name or the external name. */
128 static model_info *locate_model(const char *name)
130 model_info *p;
132 /* Try cpuinfo name first */
133 for (p = models; p != models + sizeof models / sizeof models[0]; ++p) {
134 if (strcmp(p->cpuinfo_name, name) == 0) return p; // found it
137 /* Now try external name */
138 for (p = models; p != models + sizeof models / sizeof models[0]; ++p) {
139 if (strcmp(p->real_name, name) == 0) return p; // found it
142 return NULL;
146 static model_info *get_host(void)
148 int n, fh;
149 size_t num_bytes, file_buf_size;
150 char *p, *m, *model_name, *file_buf;
151 model_info *model;
153 /* Slurp contents of /proc/cpuinfo into FILE_BUF */
154 fh = open("/proc/cpuinfo", O_RDONLY, S_IRUSR);
155 if (fh < 0) return NULL;
157 /* Determine the size of /proc/cpuinfo.
158 Work around broken-ness in /proc file system implementation.
159 fstat returns a zero size for /proc/cpuinfo although it is
160 claimed to be a regular file. */
161 num_bytes = 0;
162 file_buf_size = 1000;
163 file_buf = malloc(file_buf_size + 1);
165 while (42) {
166 n = read(fh, file_buf, file_buf_size);
167 if (n < 0) break;
169 num_bytes += n;
170 if (n < file_buf_size) break; /* reached EOF */
173 if (n < 0) num_bytes = 0; /* read error; ignore contents */
175 if (num_bytes > file_buf_size) {
176 free(file_buf);
177 lseek(fh, 0, SEEK_SET);
178 file_buf = malloc(num_bytes + 1);
179 n = read(fh, file_buf, num_bytes);
180 if (n < 0) num_bytes = 0;
183 file_buf[num_bytes] = '\0';
184 close(fh);
186 /* Parse file */
187 model = models + sizeof models / sizeof models[0];
188 for (p = file_buf; *p; ++p) {
189 /* Beginning of line */
190 if (strncmp(p, "processor", sizeof "processor" - 1 ) != 0) continue;
192 m = strstr(p, "machine");
193 if (m == NULL) continue;
195 p = m + sizeof "machine" - 1;
196 while (isspace(*p) || *p == '=') {
197 if (*p == '\n') goto next_line;
198 ++p;
201 model_name = p;
202 for (n = 0; n < sizeof models / sizeof models[0]; ++n) {
203 model_info *mm = models + n;
204 size_t len = strlen(mm->cpuinfo_name);
205 if (strncmp(mm->cpuinfo_name, model_name, len) == 0 &&
206 isspace(model_name[len])) {
207 /* In case there are different CPUs in this cluster return the
208 one with the dewest capabilities ("oldest" model). */
209 if (mm < model) model = mm;
210 p = model_name + len;
211 break;
214 /* Skip until end-of-line */
215 while (*p != '\n')
216 ++p;
217 next_line: ;
220 free(file_buf);
222 if (model == models + sizeof models / sizeof models[0]) return NULL;
224 return model;
228 /* Convenience macro that maps the facility bit number as given in the
229 Principles of Ops "facility indications" section to a bit mask */
230 #define FAC_BIT(x) (1ULL << (63 - (x)))
232 static int go(char *feature, char *cpu)
234 unsigned long long facilities[S390_NUM_FACILITY_DW];
235 unsigned long long match;
236 model_info *host, *from, *to, *p;
237 char *colon;
239 clear_facilities(facilities);
240 stfle(facilities);
242 if (strcmp(feature, "s390x-zarch") == 0 ) {
243 match = (facilities[0] & FAC_BIT(1)) && (facilities[0] & FAC_BIT(2));
244 } else if (strcmp(feature, "s390x-n3") == 0 ) {
245 match = facilities[0] & FAC_BIT(0);
246 } else if (strcmp(feature, "s390x-stfle") == 0 ) {
247 match = facilities[0] & FAC_BIT(7);
248 } else if (strcmp(feature, "s390x-ldisp") == 0 ) {
249 match = (facilities[0] & FAC_BIT(18)) && (facilities[0] & FAC_BIT(19));
250 } else if (strcmp(feature, "s390x-eimm") == 0 ) {
251 match = facilities[0] & FAC_BIT(21);
252 } else if (strcmp(feature, "s390x-stckf") == 0 ) {
253 match = facilities[0] & FAC_BIT(25);
254 } else if (strcmp(feature, "s390x-genins") == 0 ) {
255 match = facilities[0] & FAC_BIT(34);
256 } else if (strcmp(feature, "s390x-exrl") == 0 ) {
257 match = facilities[0] & FAC_BIT(35);
258 } else if (strcmp(feature, "s390x-etf3") == 0 ) {
259 match = facilities[0] & FAC_BIT(30);
260 } else if (strcmp(feature, "s390x-fpext") == 0 ) {
261 match = facilities[0] & FAC_BIT(37);
262 } else if (strcmp(feature, "s390x-dfp") == 0 ) {
263 match = facilities[0] & FAC_BIT(42);
264 } else if (strcmp(feature, "s390x-pfpo") == 0 ) {
265 match = facilities[0] & FAC_BIT(44);
266 } else if (strcmp(feature, "s390x-highw") == 0 ) {
267 match = facilities[0] & FAC_BIT(45);
268 } else if (strcmp(feature, "s390x-vx") == 0 ) {
269 /* VX needs kernel support; thus check the appropriate HWCAP bit. */
270 match = GET_HWCAP() & 0x800;
271 } else if (strcmp(feature, "s390x-msa5") == 0 ) {
272 match = facilities[0] & FAC_BIT(57); /* message security assist 5 facility */
273 } else if (strcmp(feature, "s390x-mi2") == 0 ) {
274 match = facilities[0] & FAC_BIT(58);
275 } else if (strcmp(feature, "s390x-mi3") == 0 ) {
276 match = facilities[0] & FAC_BIT(61);
277 } else if (strcmp(feature, "s390x-vx2") == 0 ) {
278 match = (GET_HWCAP() & 0x800) && (facilities[2] & FAC_BIT(20));
279 } else {
280 return 2; // Unrecognised feature.
283 if (match == 0) return 1; // facility not provided
285 /* Host provides facility. If no CPU was specified, we're done. */
286 if (cpu == NULL) return 0;
288 host = get_host();
289 if (host == NULL) return 1; // unknown model
291 // printf("host = %s (%s)\n", host->cpuinfo_name, host->real_name);
293 /* Determine interval of models in which to search for HOST. */
294 from = to = NULL;
295 colon = strchr(cpu, ':');
297 if (colon == NULL) {
298 // match exact
299 from = to = locate_model(cpu);
300 } else if (colon == cpu) {
301 // :NAME match machines up to and including CPU
302 from = models;
303 to = locate_model(cpu + 1);
304 } else if (colon[1] == '\0') {
305 // NAME: match machines beginning with CPU or later
306 *colon = '\0';
307 from = locate_model(cpu);
308 to = models + sizeof models / sizeof models[0] - 1;
309 *colon = ':';
310 } else {
311 // NAME:NAME match machines in interval
312 *colon = '\0';
313 from = locate_model(cpu);
314 to = locate_model(colon + 1);
315 *colon = ':';
318 if (from == NULL || to == NULL || from > to) {
319 fprintf(stderr, "invalid cpu specification '%s'\n", cpu);
320 return 3;
323 #if 0
324 printf("from %s (%s) to %s (%s)\n", from->cpuinfo_name, from->real_name,
325 to->cpuinfo_name, to->real_name);
326 #endif
328 /* Search for HOST. */
329 for (p = from; p <= to; ++p) {
330 if (p == host) return 0;
333 return 1; // host does not match CPU specification
336 #else
338 static int go(char *feature, char *cpu)
340 return 2; // Feature not recognised (non-s390x machine!)
343 #endif
346 //---------------------------------------------------------------------------
347 // main
348 //---------------------------------------------------------------------------
349 int main(int argc, char **argv)
351 int rc, inverted = 0;
353 if (argc < 2 || argc > 3) {
354 fprintf( stderr, "usage: s390x_features <feature> [<machine-model>]\n" );
355 exit(3); // Usage error.
358 if (argv[1][0] == '!') {
359 assert(argv[2] == NULL); // not allowed
360 inverted = 1;
361 ++argv[1];
364 rc = go(argv[1], argv[2]);
366 if (inverted) {
367 switch (rc) {
368 case 0: rc = 1; break;
369 case 1: rc = 0; break;
370 case 2: rc = 2; break;
374 // printf("rc = %d\n", rc);
376 return rc;