1ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian/* -*- mode: C; c-basic-offset: 3; -*- */
2ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
302b89e887521d3f4e0cb0d3408eb3f462142f932sewardj#include <setjmp.h>
402b89e887521d3f4e0cb0d3408eb3f462142f932sewardj#include <signal.h>
502b89e887521d3f4e0cb0d3408eb3f462142f932sewardj#include <stdio.h>
602b89e887521d3f4e0cb0d3408eb3f462142f932sewardj#include <stdlib.h>
702b89e887521d3f4e0cb0d3408eb3f462142f932sewardj#include <string.h>
8a066ccdcfd4e6f20fada0e772e279dc2035cb930florian#include <assert.h>
9ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian#include <ctype.h>     // isspace
10ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian#include <fcntl.h>     // open
11ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian#include <unistd.h>    // lseek
12ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian#include <sys/stat.h>  // S_IRUSR
1302b89e887521d3f4e0cb0d3408eb3f462142f932sewardj
1402b89e887521d3f4e0cb0d3408eb3f462142f932sewardj// This file determines s390x features a processor supports.
1502b89e887521d3f4e0cb0d3408eb3f462142f932sewardj//
1602b89e887521d3f4e0cb0d3408eb3f462142f932sewardj// We return:
17ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian// - 0 if the machine provides the asked-for feature and the cpu
18ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian//     model, if specified, matches the machine
19ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian// - 1 the machine does not provide the asked-for feature or the
20ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian//     cpu model, if specified, does not match the machine
219dd35e05acd69b52ed4d59295f70826edef77c92cborntra// - 1 for an unknown cpu model in /proc/cpu_info
2202b89e887521d3f4e0cb0d3408eb3f462142f932sewardj// - 2 if the asked-for feature isn't recognised (this will be the case for
2302b89e887521d3f4e0cb0d3408eb3f462142f932sewardj//     any feature if run on a non-s390x machine).
2402b89e887521d3f4e0cb0d3408eb3f462142f932sewardj// - 3 if there was a usage error (it also prints an error message).
25ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian//
26ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian// USAGE:
27ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian//
28ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian//    s390x_features <feature> [<machine-model>]
29ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian//
30ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian// The machine_model is optional and it can be something like:
31ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian//
32ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian//   z9        -- Host needs to be a z9 (and nothing else)
33ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian//   z9:       -- Host needs to be a z9 or any later model
34ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian//   :z9       -- Host needs to be a model up to and including z9
35ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian//   z900:z9   -- Host needs to be at least a z900 and at most a z9.
36ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian//                Any model in between is OK, too.
3702b89e887521d3f4e0cb0d3408eb3f462142f932sewardj
3802b89e887521d3f4e0cb0d3408eb3f462142f932sewardjjmp_buf env;
3902b89e887521d3f4e0cb0d3408eb3f462142f932sewardj
4002b89e887521d3f4e0cb0d3408eb3f462142f932sewardj#if defined(VGA_s390x)
4102b89e887521d3f4e0cb0d3408eb3f462142f932sewardj
4202b89e887521d3f4e0cb0d3408eb3f462142f932sewardjvoid handle_sigill(int signum)
4302b89e887521d3f4e0cb0d3408eb3f462142f932sewardj{
4402b89e887521d3f4e0cb0d3408eb3f462142f932sewardj   longjmp(env, 1);
4502b89e887521d3f4e0cb0d3408eb3f462142f932sewardj}
4602b89e887521d3f4e0cb0d3408eb3f462142f932sewardj
4702b89e887521d3f4e0cb0d3408eb3f462142f932sewardjunsigned long long stfle(void)
4802b89e887521d3f4e0cb0d3408eb3f462142f932sewardj{
4902b89e887521d3f4e0cb0d3408eb3f462142f932sewardj
5002b89e887521d3f4e0cb0d3408eb3f462142f932sewardj   unsigned long long ret;
5102b89e887521d3f4e0cb0d3408eb3f462142f932sewardj
5202b89e887521d3f4e0cb0d3408eb3f462142f932sewardj   signal(SIGILL, handle_sigill);
5302b89e887521d3f4e0cb0d3408eb3f462142f932sewardj   if (setjmp(env)) {
5402b89e887521d3f4e0cb0d3408eb3f462142f932sewardj      /* stfle not available: assume no facilities */
5502b89e887521d3f4e0cb0d3408eb3f462142f932sewardj      return 0;
5602b89e887521d3f4e0cb0d3408eb3f462142f932sewardj   } else {
5702b89e887521d3f4e0cb0d3408eb3f462142f932sewardj      asm volatile("lghi 0, 0\n"
5802b89e887521d3f4e0cb0d3408eb3f462142f932sewardj                   ".insn s,0xb2b00000,%0\n" /* stfle */
5902b89e887521d3f4e0cb0d3408eb3f462142f932sewardj      : "=Q" (ret)::"0", "cc");
6002b89e887521d3f4e0cb0d3408eb3f462142f932sewardj      return ret;
6102b89e887521d3f4e0cb0d3408eb3f462142f932sewardj   }
6202b89e887521d3f4e0cb0d3408eb3f462142f932sewardj}
6302b89e887521d3f4e0cb0d3408eb3f462142f932sewardj
64ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
65ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian/* Read /proc/cpuinfo. Look for lines like these
66ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
67ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      processor 0: version = FF,  identification = 0117C9,  machine = 2064
68ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
69ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   and return the machine model or NULL on error.
70ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   Adapted from function VG_(get_machine_model) in coregrind/m_machine.c */
71ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
72ec82dd9de08eaf9d6d5c6b1ebaec53039e371903floriantypedef struct {
73ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   const char *cpuinfo_name;
74ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   const char *real_name;
75ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian} model_info;
76ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
77ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian/* Array needs to be sorted chronologically. Oldest to newest */
78ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florianmodel_info models[] = {
79ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   { "2064", "z900"   },
80ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   { "2066", "z800"   },
81ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   { "2084", "z990"   },
82ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   { "2086", "z890"   },
8387a25cf59352617f8876b8bdc8d437d4aafe5ae3florian   { "2094", "z9-EC"  },
8487a25cf59352617f8876b8bdc8d437d4aafe5ae3florian   { "2096", "z9-BC"  },
8587a25cf59352617f8876b8bdc8d437d4aafe5ae3florian   { "2097", "z10-EC" },
8687a25cf59352617f8876b8bdc8d437d4aafe5ae3florian   { "2098", "z10-BC" },
87ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   { "2817", "z196"   },
889dd35e05acd69b52ed4d59295f70826edef77c92cborntra   { "2818", "z114"   },
8987a25cf59352617f8876b8bdc8d437d4aafe5ae3florian   { "2827", "zEC12"  },
903b411c169c685099c2fc26d816d4eac29fca6573florian   { "2828", "zBC12"  },
91dd1d372ee14d89793942cea99296853253a664edflorian   { "2964", "z13"    },
92a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes   { "2965", "z13s"   },
93ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian};
94ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
95ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
96ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian/* Locate a machine model by name. Name can be either the cpuinfo
97ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   name or the external name. */
98ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florianstatic model_info *locate_model(const char *name)
99ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian{
100ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   model_info *p;
101ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
102ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   /* Try cpuinfo name first */
103ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   for (p = models; p != models + sizeof models / sizeof models[0]; ++p) {
104ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      if (strcmp(p->cpuinfo_name, name) == 0) return p;  // found it
105ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   }
106ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
107ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   /* Now try external name */
108ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   for (p = models; p != models + sizeof models / sizeof models[0]; ++p) {
109ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      if (strcmp(p->real_name, name) == 0) return p;  // found it
110ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   }
111ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
112ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   return NULL;
113ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian}
114ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
115ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
116ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florianstatic model_info *get_host(void)
117ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian{
118ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   int    n, fh;
119ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   size_t num_bytes, file_buf_size;
120ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   char  *p, *m, *model_name, *file_buf;
121ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   model_info *model;
122ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
123ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   /* Slurp contents of /proc/cpuinfo into FILE_BUF */
124ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   fh = open("/proc/cpuinfo", O_RDONLY, S_IRUSR);
125ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   if (fh < 0) return NULL;
126ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
127ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   /* Determine the size of /proc/cpuinfo.
128ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      Work around broken-ness in /proc file system implementation.
129ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      fstat returns a zero size for /proc/cpuinfo although it is
130ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      claimed to be a regular file. */
131ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   num_bytes = 0;
132ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   file_buf_size = 1000;
133ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   file_buf = malloc(file_buf_size + 1);
134ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
135ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   while (42) {
136ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      n = read(fh, file_buf, file_buf_size);
137ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      if (n < 0) break;
138ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
139ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      num_bytes += n;
140ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      if (n < file_buf_size) break;  /* reached EOF */
141ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   }
142ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
143ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   if (n < 0) num_bytes = 0;   /* read error; ignore contents */
144ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
145ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   if (num_bytes > file_buf_size) {
146ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      free(file_buf);
147ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      lseek(fh, 0, SEEK_SET);
148ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      file_buf = malloc(num_bytes + 1);
149ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      n = read(fh, file_buf, num_bytes);
150ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      if (n < 0) num_bytes = 0;
151ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   }
152ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
153ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   file_buf[num_bytes] = '\0';
154ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   close(fh);
155ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
156ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   /* Parse file */
157ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   model = models + sizeof models / sizeof models[0];
158ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   for (p = file_buf; *p; ++p) {
159ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      /* Beginning of line */
160ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      if (strncmp(p, "processor", sizeof "processor" - 1 ) != 0) continue;
161ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
162ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      m = strstr(p, "machine");
163ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      if (m == NULL) continue;
164ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
165ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      p = m + sizeof "machine" - 1;
166ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      while (isspace(*p) || *p == '=') {
167ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian         if (*p == '\n') goto next_line;
168ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian         ++p;
169ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      }
170ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
171ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      model_name = p;
172ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      for (n = 0; n < sizeof models / sizeof models[0]; ++n) {
173ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian         model_info *mm = models + n;
174ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian         size_t len = strlen(mm->cpuinfo_name);
175ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian         if (strncmp(mm->cpuinfo_name, model_name, len) == 0 &&
176ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian             isspace(model_name[len])) {
177ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian            /* In case there are different CPUs in this cluster return the
178ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian               one with the dewest capabilities ("oldest" model). */
179ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian            if (mm < model) model = mm;
180ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian            p = model_name + len;
181ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian            break;
182ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian         }
183ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      }
184ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      /* Skip until end-of-line */
185ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      while (*p != '\n')
186ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian         ++p;
187ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   next_line: ;
188ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   }
189ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
190ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   free(file_buf);
191ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
192ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   if (model == models + sizeof models / sizeof models[0]) return NULL;
193ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
194ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   return model;
195ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian}
196ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
1974bc35a8615523bd9f23d6104aacb9662ca72f316florian
1984bc35a8615523bd9f23d6104aacb9662ca72f316florian/* Convenience macro that maps the facility bit number as given in the
1994bc35a8615523bd9f23d6104aacb9662ca72f316florian   Principles of Ops "facility indications" section to a bit mask */
2004bc35a8615523bd9f23d6104aacb9662ca72f316florian#define FAC_BIT(x)   (1ULL << (63 - (x)))
2014bc35a8615523bd9f23d6104aacb9662ca72f316florian
202ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florianstatic int go(char *feature, char *cpu)
20302b89e887521d3f4e0cb0d3408eb3f462142f932sewardj{
20402b89e887521d3f4e0cb0d3408eb3f462142f932sewardj   unsigned long long facilities;
20502b89e887521d3f4e0cb0d3408eb3f462142f932sewardj   unsigned long long match;
206ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   model_info *host, *from, *to, *p;
207ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   char *colon;
20802b89e887521d3f4e0cb0d3408eb3f462142f932sewardj
20902b89e887521d3f4e0cb0d3408eb3f462142f932sewardj   facilities = stfle();
21002b89e887521d3f4e0cb0d3408eb3f462142f932sewardj
211ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   if        (strcmp(feature, "s390x-zarch") == 0 ) {
2124bc35a8615523bd9f23d6104aacb9662ca72f316florian      match = (facilities & FAC_BIT(1)) && (facilities & FAC_BIT(2));
213ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   } else if (strcmp(feature, "s390x-n3") == 0 ) {
2144bc35a8615523bd9f23d6104aacb9662ca72f316florian      match = facilities & FAC_BIT(0);
215ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   } else if (strcmp(feature, "s390x-stfle") == 0 ) {
2164bc35a8615523bd9f23d6104aacb9662ca72f316florian      match = facilities & FAC_BIT(7);
217ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   } else if (strcmp(feature, "s390x-ldisp") == 0 ) {
2184bc35a8615523bd9f23d6104aacb9662ca72f316florian      match = (facilities & FAC_BIT(18)) && (facilities & FAC_BIT(19));
219ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   } else if (strcmp(feature, "s390x-eimm") == 0 ) {
2204bc35a8615523bd9f23d6104aacb9662ca72f316florian      match = facilities & FAC_BIT(21);
221ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   } else if (strcmp(feature, "s390x-stckf") == 0 ) {
2224bc35a8615523bd9f23d6104aacb9662ca72f316florian      match = facilities & FAC_BIT(25);
223ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   } else if (strcmp(feature, "s390x-genins") == 0 ) {
2244bc35a8615523bd9f23d6104aacb9662ca72f316florian      match = facilities & FAC_BIT(34);
225ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   } else if (strcmp(feature, "s390x-exrl") == 0 ) {
2264bc35a8615523bd9f23d6104aacb9662ca72f316florian      match = facilities & FAC_BIT(35);
2274b345f3cf237441639360de238837127edd72c0bflorian   } else if (strcmp(feature, "s390x-etf3") == 0 ) {
2284bc35a8615523bd9f23d6104aacb9662ca72f316florian      match = facilities & FAC_BIT(30);
229370bc773b6b0c0c4977634f6614947a448a5aa48florian   } else if (strcmp(feature, "s390x-fpext") == 0 ) {
230370bc773b6b0c0c4977634f6614947a448a5aa48florian      match = facilities & FAC_BIT(37);
23146825980db94de9a1fb0bb3398eb10862fcf2aa7florian   } else if (strcmp(feature, "s390x-dfp") == 0 ) {
23246825980db94de9a1fb0bb3398eb10862fcf2aa7florian      match = facilities & FAC_BIT(42);
2331106692158e71bade4e00a2d21548e74b2ea334eflorian   } else if (strcmp(feature, "s390x-pfpo") == 0 ) {
2341106692158e71bade4e00a2d21548e74b2ea334eflorian      match = facilities & FAC_BIT(44);
235a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes   } else if (strcmp(feature, "s390x-highw") == 0 ) {
236a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes      match = facilities & FAC_BIT(45);
23702b89e887521d3f4e0cb0d3408eb3f462142f932sewardj   } else {
2384bc35a8615523bd9f23d6104aacb9662ca72f316florian      return 2;          // Unrecognised feature.
23902b89e887521d3f4e0cb0d3408eb3f462142f932sewardj   }
24002b89e887521d3f4e0cb0d3408eb3f462142f932sewardj
241ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   if (match == 0) return 1;   // facility not provided
242ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
243ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   /* Host provides facility. If no CPU was specified, we're done. */
244ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   if (cpu == NULL) return 0;
245ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
246ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   host = get_host();
2479dd35e05acd69b52ed4d59295f70826edef77c92cborntra   if (host == NULL) return 1;  // unknown model
248ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
249ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   //   printf("host = %s (%s)\n", host->cpuinfo_name, host->real_name);
250ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
251ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   /* Determine interval of models in which to search for HOST. */
252ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   from = to = NULL;
253ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   colon = strchr(cpu, ':');
254ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
255ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   if (colon == NULL) {
256ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      // match exact
257ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      from = to = locate_model(cpu);
258ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   } else if (colon == cpu) {
259ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      // :NAME  match machines up to and including CPU
260ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      from = models;
261ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      to   = locate_model(cpu + 1);
262ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   } else if (colon[1] == '\0') {
263ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      // NAME:  match machines beginning with CPU or later
264ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      *colon = '\0';
265ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      from = locate_model(cpu);
266ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      to   = models + sizeof models / sizeof models[0] - 1;
267ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      *colon = ':';
268ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   } else {
269ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      // NAME:NAME  match machines in interval
270ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      *colon = '\0';
271ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      from = locate_model(cpu);
272ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      to   = locate_model(colon + 1);
273ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      *colon = ':';
274ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   }
275ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
276ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   if (from == NULL || to == NULL || from > to) {
277ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      fprintf(stderr, "invalid cpu specification '%s'\n", cpu);
278ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      return 3;
279ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   }
280ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
281ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian#if 0
282ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   printf("from  %s (%s)  to  %s (%s)\n", from->cpuinfo_name, from->real_name,
283ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian          to->cpuinfo_name, to->real_name);
284ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian#endif
285ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
286ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   /* Search for HOST. */
287ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   for (p = from; p <= to; ++p) {
288ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      if (p == host) return 0;
289ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   }
290ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
291ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   return 1; // host does not match CPU specification
29202b89e887521d3f4e0cb0d3408eb3f462142f932sewardj}
29302b89e887521d3f4e0cb0d3408eb3f462142f932sewardj
29402b89e887521d3f4e0cb0d3408eb3f462142f932sewardj#else
29502b89e887521d3f4e0cb0d3408eb3f462142f932sewardj
296ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florianstatic int go(char *feature, char *cpu)
29702b89e887521d3f4e0cb0d3408eb3f462142f932sewardj{
29802b89e887521d3f4e0cb0d3408eb3f462142f932sewardj   return 2;      // Feature not recognised (non-s390x machine!)
29902b89e887521d3f4e0cb0d3408eb3f462142f932sewardj}
30002b89e887521d3f4e0cb0d3408eb3f462142f932sewardj
30102b89e887521d3f4e0cb0d3408eb3f462142f932sewardj#endif
30202b89e887521d3f4e0cb0d3408eb3f462142f932sewardj
30302b89e887521d3f4e0cb0d3408eb3f462142f932sewardj
30402b89e887521d3f4e0cb0d3408eb3f462142f932sewardj//---------------------------------------------------------------------------
30502b89e887521d3f4e0cb0d3408eb3f462142f932sewardj// main
30602b89e887521d3f4e0cb0d3408eb3f462142f932sewardj//---------------------------------------------------------------------------
30702b89e887521d3f4e0cb0d3408eb3f462142f932sewardjint main(int argc, char **argv)
30802b89e887521d3f4e0cb0d3408eb3f462142f932sewardj{
309a066ccdcfd4e6f20fada0e772e279dc2035cb930florian   int rc, inverted = 0;
310ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
311ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   if (argc < 2 || argc > 3) {
312ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian      fprintf( stderr, "usage: s390x_features <feature> [<machine-model>]\n" );
31302b89e887521d3f4e0cb0d3408eb3f462142f932sewardj      exit(3);                // Usage error.
31402b89e887521d3f4e0cb0d3408eb3f462142f932sewardj   }
315ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
316a066ccdcfd4e6f20fada0e772e279dc2035cb930florian   if (argv[1][0] == '!') {
317a066ccdcfd4e6f20fada0e772e279dc2035cb930florian      assert(argv[2] == NULL);   // not allowed
318a066ccdcfd4e6f20fada0e772e279dc2035cb930florian      inverted = 1;
319a066ccdcfd4e6f20fada0e772e279dc2035cb930florian      ++argv[1];
320a066ccdcfd4e6f20fada0e772e279dc2035cb930florian   }
321a066ccdcfd4e6f20fada0e772e279dc2035cb930florian
322ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   rc = go(argv[1], argv[2]);
323a066ccdcfd4e6f20fada0e772e279dc2035cb930florian
324a066ccdcfd4e6f20fada0e772e279dc2035cb930florian   if (inverted) {
325a066ccdcfd4e6f20fada0e772e279dc2035cb930florian      switch (rc) {
326a066ccdcfd4e6f20fada0e772e279dc2035cb930florian      case 0: rc = 1; break;
327a066ccdcfd4e6f20fada0e772e279dc2035cb930florian      case 1: rc = 0; break;
328a066ccdcfd4e6f20fada0e772e279dc2035cb930florian      case 2: rc = 2; break;
329a066ccdcfd4e6f20fada0e772e279dc2035cb930florian      }
330a066ccdcfd4e6f20fada0e772e279dc2035cb930florian   }
331ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
332ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   //   printf("rc = %d\n", rc);
333ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian
334ec82dd9de08eaf9d6d5c6b1ebaec53039e371903florian   return rc;
33502b89e887521d3f4e0cb0d3408eb3f462142f932sewardj}
336