1b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* -*- mode: C; c-basic-offset: 3; -*- */
2b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
3b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include <setjmp.h>
4b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include <signal.h>
5b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include <stdio.h>
6b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include <stdlib.h>
7b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include <string.h>
8436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#include <assert.h>
9b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include <ctype.h>     // isspace
10b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include <fcntl.h>     // open
11b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include <unistd.h>    // lseek
12b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include <sys/stat.h>  // S_IRUSR
13b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
14b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov// This file determines s390x features a processor supports.
15b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov//
16b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov// We return:
17b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov// - 0 if the machine provides the asked-for feature and the cpu
18b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov//     model, if specified, matches the machine
19b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov// - 1 the machine does not provide the asked-for feature or the
20b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov//     cpu model, if specified, does not match the machine
21436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov// - 1 for an unknown cpu model in /proc/cpu_info
22b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov// - 2 if the asked-for feature isn't recognised (this will be the case for
23b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov//     any feature if run on a non-s390x machine).
24b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov// - 3 if there was a usage error (it also prints an error message).
25b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov//
26b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov// USAGE:
27b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov//
28b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov//    s390x_features <feature> [<machine-model>]
29b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov//
30b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov// The machine_model is optional and it can be something like:
31b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov//
32b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov//   z9        -- Host needs to be a z9 (and nothing else)
33b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov//   z9:       -- Host needs to be a z9 or any later model
34b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov//   :z9       -- Host needs to be a model up to and including z9
35b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov//   z900:z9   -- Host needs to be at least a z900 and at most a z9.
36b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov//                Any model in between is OK, too.
37b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
38b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovjmp_buf env;
39b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
40b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#if defined(VGA_s390x)
41b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
42b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovvoid handle_sigill(int signum)
43b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
44b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   longjmp(env, 1);
45b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
46b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
47b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovunsigned long long stfle(void)
48b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
49b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
50b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   unsigned long long ret;
51b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
52b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   signal(SIGILL, handle_sigill);
53b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (setjmp(env)) {
54b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* stfle not available: assume no facilities */
55b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      return 0;
56b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   } else {
57b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      asm volatile("lghi 0, 0\n"
58b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                   ".insn s,0xb2b00000,%0\n" /* stfle */
59b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      : "=Q" (ret)::"0", "cc");
60b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      return ret;
61b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
62b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
63b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
64b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
65b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* Read /proc/cpuinfo. Look for lines like these
66b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
67b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      processor 0: version = FF,  identification = 0117C9,  machine = 2064
68b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
69b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   and return the machine model or NULL on error.
70b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Adapted from function VG_(get_machine_model) in coregrind/m_machine.c */
71b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
72b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovtypedef struct {
73b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   const char *cpuinfo_name;
74b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   const char *real_name;
75b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov} model_info;
76b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
77b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* Array needs to be sorted chronologically. Oldest to newest */
78b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovmodel_info models[] = {
79b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   { "2064", "z900"   },
80b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   { "2066", "z800"   },
81b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   { "2084", "z990"   },
82b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   { "2086", "z890"   },
83436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   { "2094", "z9-EC"  },
84436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   { "2096", "z9-BC"  },
85436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   { "2097", "z10-EC" },
86436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   { "2098", "z10-BC" },
87b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   { "2817", "z196"   },
88436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   { "2818", "z114"   },
89436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   { "2827", "zEC12"  },
90436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   { "2828", "zBC12"  },
91b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov};
92b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
93b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
94b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* Locate a machine model by name. Name can be either the cpuinfo
95b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   name or the external name. */
96b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic model_info *locate_model(const char *name)
97b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
98b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   model_info *p;
99b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
100b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* Try cpuinfo name first */
101b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   for (p = models; p != models + sizeof models / sizeof models[0]; ++p) {
102b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (strcmp(p->cpuinfo_name, name) == 0) return p;  // found it
103b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
104b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
105b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* Now try external name */
106b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   for (p = models; p != models + sizeof models / sizeof models[0]; ++p) {
107b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (strcmp(p->real_name, name) == 0) return p;  // found it
108b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
109b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
110b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   return NULL;
111b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
112b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
113b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
114b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic model_info *get_host(void)
115b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
116b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   int    n, fh;
117b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   size_t num_bytes, file_buf_size;
118b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   char  *p, *m, *model_name, *file_buf;
119b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   model_info *model;
120b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
121b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* Slurp contents of /proc/cpuinfo into FILE_BUF */
122b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   fh = open("/proc/cpuinfo", O_RDONLY, S_IRUSR);
123b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (fh < 0) return NULL;
124b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
125b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* Determine the size of /proc/cpuinfo.
126b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      Work around broken-ness in /proc file system implementation.
127b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      fstat returns a zero size for /proc/cpuinfo although it is
128b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      claimed to be a regular file. */
129b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   num_bytes = 0;
130b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   file_buf_size = 1000;
131b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   file_buf = malloc(file_buf_size + 1);
132b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
133b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   while (42) {
134b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      n = read(fh, file_buf, file_buf_size);
135b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (n < 0) break;
136b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
137b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      num_bytes += n;
138b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (n < file_buf_size) break;  /* reached EOF */
139b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
140b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
141b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (n < 0) num_bytes = 0;   /* read error; ignore contents */
142b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
143b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (num_bytes > file_buf_size) {
144b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      free(file_buf);
145b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      lseek(fh, 0, SEEK_SET);
146b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      file_buf = malloc(num_bytes + 1);
147b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      n = read(fh, file_buf, num_bytes);
148b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (n < 0) num_bytes = 0;
149b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
150b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
151b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   file_buf[num_bytes] = '\0';
152b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   close(fh);
153b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
154b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* Parse file */
155b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   model = models + sizeof models / sizeof models[0];
156b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   for (p = file_buf; *p; ++p) {
157b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* Beginning of line */
158b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (strncmp(p, "processor", sizeof "processor" - 1 ) != 0) continue;
159b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
160b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      m = strstr(p, "machine");
161b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (m == NULL) continue;
162b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
163b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      p = m + sizeof "machine" - 1;
164b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      while (isspace(*p) || *p == '=') {
165b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (*p == '\n') goto next_line;
166b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         ++p;
167b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      }
168b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
169b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      model_name = p;
170b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      for (n = 0; n < sizeof models / sizeof models[0]; ++n) {
171b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         model_info *mm = models + n;
172b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         size_t len = strlen(mm->cpuinfo_name);
173b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (strncmp(mm->cpuinfo_name, model_name, len) == 0 &&
174b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov             isspace(model_name[len])) {
175b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            /* In case there are different CPUs in this cluster return the
176b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               one with the dewest capabilities ("oldest" model). */
177b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            if (mm < model) model = mm;
178b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            p = model_name + len;
179b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            break;
180b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         }
181b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      }
182b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* Skip until end-of-line */
183b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      while (*p != '\n')
184b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         ++p;
185b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   next_line: ;
186b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
187b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
188b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   free(file_buf);
189b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
190b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (model == models + sizeof models / sizeof models[0]) return NULL;
191b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
192b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   return model;
193b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
194b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
195436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
196436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/* Convenience macro that maps the facility bit number as given in the
197436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Principles of Ops "facility indications" section to a bit mask */
198436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#define FAC_BIT(x)   (1ULL << (63 - (x)))
199436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
200b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic int go(char *feature, char *cpu)
201b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
202b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   unsigned long long facilities;
203b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   unsigned long long match;
204b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   model_info *host, *from, *to, *p;
205b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   char *colon;
206b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
207b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   facilities = stfle();
208b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
209b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if        (strcmp(feature, "s390x-zarch") == 0 ) {
210436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      match = (facilities & FAC_BIT(1)) && (facilities & FAC_BIT(2));
211b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   } else if (strcmp(feature, "s390x-n3") == 0 ) {
212436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      match = facilities & FAC_BIT(0);
213b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   } else if (strcmp(feature, "s390x-stfle") == 0 ) {
214436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      match = facilities & FAC_BIT(7);
215b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   } else if (strcmp(feature, "s390x-ldisp") == 0 ) {
216436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      match = (facilities & FAC_BIT(18)) && (facilities & FAC_BIT(19));
217b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   } else if (strcmp(feature, "s390x-eimm") == 0 ) {
218436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      match = facilities & FAC_BIT(21);
219b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   } else if (strcmp(feature, "s390x-stckf") == 0 ) {
220436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      match = facilities & FAC_BIT(25);
221b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   } else if (strcmp(feature, "s390x-genins") == 0 ) {
222436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      match = facilities & FAC_BIT(34);
223b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   } else if (strcmp(feature, "s390x-exrl") == 0 ) {
224436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      match = facilities & FAC_BIT(35);
225436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   } else if (strcmp(feature, "s390x-etf3") == 0 ) {
226436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      match = facilities & FAC_BIT(30);
227436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   } else if (strcmp(feature, "s390x-fpext") == 0 ) {
228436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      match = facilities & FAC_BIT(37);
229436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   } else if (strcmp(feature, "s390x-dfp") == 0 ) {
230436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      match = facilities & FAC_BIT(42);
231436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   } else if (strcmp(feature, "s390x-pfpo") == 0 ) {
232436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      match = facilities & FAC_BIT(44);
233b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   } else {
234436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      return 2;          // Unrecognised feature.
235b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
236b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
237b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (match == 0) return 1;   // facility not provided
238b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
239b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* Host provides facility. If no CPU was specified, we're done. */
240b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (cpu == NULL) return 0;
241b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
242b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   host = get_host();
243436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (host == NULL) return 1;  // unknown model
244b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
245b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   //   printf("host = %s (%s)\n", host->cpuinfo_name, host->real_name);
246b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
247b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* Determine interval of models in which to search for HOST. */
248b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   from = to = NULL;
249b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   colon = strchr(cpu, ':');
250b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
251b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (colon == NULL) {
252b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      // match exact
253b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      from = to = locate_model(cpu);
254b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   } else if (colon == cpu) {
255b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      // :NAME  match machines up to and including CPU
256b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      from = models;
257b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      to   = locate_model(cpu + 1);
258b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   } else if (colon[1] == '\0') {
259b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      // NAME:  match machines beginning with CPU or later
260b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      *colon = '\0';
261b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      from = locate_model(cpu);
262b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      to   = models + sizeof models / sizeof models[0] - 1;
263b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      *colon = ':';
264b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   } else {
265b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      // NAME:NAME  match machines in interval
266b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      *colon = '\0';
267b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      from = locate_model(cpu);
268b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      to   = locate_model(colon + 1);
269b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      *colon = ':';
270b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
271b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
272b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (from == NULL || to == NULL || from > to) {
273b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      fprintf(stderr, "invalid cpu specification '%s'\n", cpu);
274b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      return 3;
275b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
276b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
277b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#if 0
278b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   printf("from  %s (%s)  to  %s (%s)\n", from->cpuinfo_name, from->real_name,
279b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov          to->cpuinfo_name, to->real_name);
280b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#endif
281b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
282b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* Search for HOST. */
283b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   for (p = from; p <= to; ++p) {
284b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (p == host) return 0;
285b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
286b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
287b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   return 1; // host does not match CPU specification
288b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
289b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
290b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#else
291b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
292b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic int go(char *feature, char *cpu)
293b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
294b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   return 2;      // Feature not recognised (non-s390x machine!)
295b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
296b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
297b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#endif
298b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
299b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
300b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov//---------------------------------------------------------------------------
301b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov// main
302b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov//---------------------------------------------------------------------------
303b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovint main(int argc, char **argv)
304b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
305436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   int rc, inverted = 0;
306b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
307b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (argc < 2 || argc > 3) {
308b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      fprintf( stderr, "usage: s390x_features <feature> [<machine-model>]\n" );
309b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      exit(3);                // Usage error.
310b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
311b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
312436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (argv[1][0] == '!') {
313436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      assert(argv[2] == NULL);   // not allowed
314436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      inverted = 1;
315436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      ++argv[1];
316436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
317436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
318b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   rc = go(argv[1], argv[2]);
319436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
320436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (inverted) {
321436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      switch (rc) {
322436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0: rc = 1; break;
323436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 1: rc = 0; break;
324436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 2: rc = 2; break;
325436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      }
326436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
327b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
328b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   //   printf("rc = %d\n", rc);
329b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
330b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   return rc;
331b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
332