1 /*
   2  * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 #include "logging/log.hpp"
  26 #include "precompiled.hpp"
  27 #include "runtime/os.hpp"
  28 #include "runtime/vm_version.hpp"
  29 
  30 
  31 #define CPUINFO_LINE_SIZE 1024
  32 
  33 
  34 class CPUinfo {
  35 public:
  36   CPUinfo(const char* field) : _string(NULL) {
  37 
  38     char line[CPUINFO_LINE_SIZE];
  39     FILE* fp = fopen("/proc/cpuinfo", "r");
  40 
  41     if (fp != NULL) {
  42       while (fgets(line, sizeof(line), fp) != NULL) {
  43         assert(strlen(line) < sizeof(line) - 1,
  44                "buffer too small (%d)", CPUINFO_LINE_SIZE);
  45 
  46         const char* vstr = match_field(line, field);
  47 
  48         if (vstr != NULL) {
  49           // We have a matching line and a valid starting point to the value of
  50           // the field, copy the string for keeps.
  51           _string = strdup(vstr);
  52           break;
  53         }
  54       }
  55       fclose(fp);
  56     }
  57   }
  58 
  59   ~CPUinfo() { free((void*)_string); }
  60 
  61   const char* value() const { return _string; }
  62 
  63   bool valid() const { return _string != NULL; }
  64 
  65   bool match(const char* s) const {
  66     return valid() ? strcmp(_string, s) == 0 : false;
  67   }
  68 
  69 private:
  70   const char* _string;
  71 
  72   const char* match_field(char line[CPUINFO_LINE_SIZE], const char* field);
  73   const char* match_alo(const char* text, const char* exp);
  74   const char* match_seq(const char* text, const char* seq);
  75 };
  76 
  77 /* Given a line of text read from /proc/cpuinfo, determine if the property header
  78  * matches the field specified, according to the following regexp: "<field>"\W+:\W+
  79  *
  80  * If we have a matching expression, return a pointer to the first character after
  81  * the matching pattern, i.e. the "value", otherwise return NULL.
  82  */
  83 const char* CPUinfo::match_field(char line[CPUINFO_LINE_SIZE], const char* field) {
  84   return match_alo(match_seq(match_alo(match_seq(line, field), "\t "), ":"), "\t ");
  85 }
  86 
  87 /* Match a sequence of at-least-one character in the string expression (exp) to
  88  * the text input.
  89  */
  90 const char* CPUinfo::match_alo(const char* text, const char* exp) {
  91   if (text == NULL) return NULL;
  92 
  93   const char* chp;
  94 
  95   for (chp = &text[0]; *chp != '\0'; chp++) {
  96     if (strchr(exp, *chp) == NULL) break;
  97   }
  98 
  99   return text < chp ? chp : NULL;
 100 }
 101 
 102 /* Match an exact sequence of characters as specified by the string expression
 103  * (seq) to the text input.
 104  */
 105 const char* CPUinfo::match_seq(const char* text, const char* seq) {
 106   if (text == NULL) return NULL;
 107 
 108   while (*seq != '\0') {
 109     if (*seq != *text++) break; else seq++;
 110   }
 111 
 112   return *seq == '\0' ? text : NULL;
 113 }
 114 
 115 
 116 typedef struct {
 117   const uint32_t    hash;
 118   bool              seen;
 119   const char* const name;
 120   const uint64_t    mask;
 121 } FeatureEntry;
 122 
 123 
 124 static uint64_t parse_features(FeatureEntry feature_tbl[], const char input[]);
 125 
 126 
 127 void VM_Version::platform_features() {
 128 
 129   // Some of the features reported via "cpucaps", such as; 'flush', 'stbar',
 130   // 'swap', 'muldiv', 'ultra3', 'blkinit', 'n2', 'mul32', 'div32', 'fsmuld'
 131   // and 'v8plus', are either SPARC V8, supported by all HW or simply nonsense
 132   // (the 'ultra3' "property").
 133   //
 134   // Entries marked as 'NYI' are not yet supported via "cpucaps" but are
 135   // expected to have the names used in the table below (these are SPARC M7
 136   // features or more recent).
 137   //
 138   // NOTE: Table sorted on lookup/hash ID.
 139 
 140   static FeatureEntry s_feature_tbl[] = {
 141     { 0x006f, false, "v9",         ISA_v9_msk },            // Mandatory
 142     { 0x00a6, false, "md5",        ISA_md5_msk },
 143     { 0x00ce, false, "adi",        ISA_adi_msk },           // NYI
 144     { 0x00d7, false, "ima",        ISA_ima_msk },
 145     { 0x00d9, false, "aes",        ISA_aes_msk },
 146     { 0x00db, false, "hpc",        ISA_hpc_msk },
 147     { 0x00dc, false, "des",        ISA_des_msk },
 148     { 0x00ed, false, "sha1",       ISA_sha1_msk },
 149     { 0x00f2, false, "vis",        ISA_vis1_msk },
 150     { 0x0104, false, "vis2",       ISA_vis2_msk },
 151     { 0x0105, false, "vis3",       ISA_vis3_msk },
 152     { 0x0114, false, "sha512",     ISA_sha512_msk },
 153     { 0x0119, false, "sha256",     ISA_sha256_msk },
 154     { 0x011a, false, "fmaf",       ISA_fmaf_msk },
 155     { 0x0132, false, "popc",       ISA_popc_msk },
 156     { 0x0140, false, "crc32c",     ISA_crc32c_msk },
 157     { 0x0147, false, "vis3b",      ISA_vis3b_msk },         // NYI
 158     { 0x017e, false, "pause",      ISA_pause_msk },
 159     { 0x0182, false, "mwait",      ISA_mwait_msk },         // NYI
 160     { 0x018b, false, "mpmul",      ISA_mpmul_msk },
 161     { 0x018e, false, "sparc5",     ISA_sparc5_msk },        // NYI
 162     { 0x01a9, false, "cbcond",     ISA_cbcond_msk },
 163     { 0x01c3, false, "vamask",     ISA_vamask_msk },        // NYI
 164     { 0x01ca, false, "kasumi",     ISA_kasumi_msk },
 165     { 0x01e3, false, "xmpmul",     ISA_xmpmul_msk },        // NYI
 166     { 0x022c, false, "montmul",    ISA_mont_msk },
 167     { 0x0234, false, "montsqr",    ISA_mont_msk },
 168     { 0x0238, false, "camellia",   ISA_camellia_msk },
 169     { 0x024a, false, "ASIBlkInit", ISA_blk_init_msk },
 170     { 0x0284, false, "xmontmul",   ISA_xmont_msk },         // NYI
 171     { 0x02e6, false, "pause_nsec", ISA_pause_nsec_msk },    // NYI
 172 
 173     { 0x0000, false, NULL, 0 }
 174   };
 175 
 176   CPUinfo caps("cpucaps");      // Read "cpucaps" from /proc/cpuinfo.
 177 
 178   assert(caps.valid(), "must be");
 179 
 180   _features = parse_features(s_feature_tbl, caps.value());
 181 
 182   assert(has_v9(), "must be");  // Basic SPARC-V9 required (V8 not supported).
 183 
 184   CPUinfo type("type");
 185 
 186   bool is_sun4v = type.match("sun4v");   // All Oracle SPARC + Fujitsu Athena+
 187   bool is_sun4u = type.match("sun4u");   // All other Fujitsu
 188 
 189   uint64_t synthetic = 0;
 190 
 191   if (is_sun4v) {
 192     // Indirect and direct branches are equally fast.
 193     synthetic = CPU_fast_ind_br_msk;
 194     // Fast IDIV, BIS and LD available on Niagara Plus.
 195     if (has_vis2()) {
 196       synthetic |= (CPU_fast_idiv_msk | CPU_fast_ld_msk);
 197       // ...on Core C4 however, we prefer not to use BIS.
 198       if (!has_sparc5()) {
 199         synthetic |= CPU_fast_bis_msk;
 200       }
 201     }
 202     // Niagara Core C3 supports fast RDPC and block zeroing.
 203     if (has_ima()) {
 204       synthetic |= (CPU_fast_rdpc_msk | CPU_blk_zeroing_msk);
 205     }
 206     // Niagara Core C3 and C4 have slow CMOVE.
 207     if (!has_ima()) {
 208       synthetic |= CPU_fast_cmove_msk;
 209     }
 210   } else if (is_sun4u) {
 211     // SPARC64 only have fast IDIV and RDPC.
 212     synthetic |= (CPU_fast_idiv_msk | CPU_fast_rdpc_msk);
 213   } else {
 214     log_info(os, cpu)("Unable to derive CPU features: %s", type.value());
 215   }
 216 
 217   _features += synthetic;   // Including CPU derived/synthetic features.
 218 }
 219 
 220 
 221 ////////////////////////////////////////////////////////////////////////////////
 222 
 223 static uint32_t uhash32(const char name[]);
 224 
 225 static void update_table(FeatureEntry feature_tbl[], uint32_t hv,
 226                          const char* ch1p,
 227                          const char* endp);
 228 
 229 /* Given a feature table, parse the input text holding the string value of
 230  * 'cpucaps' as reported by '/proc/cpuinfo', in order to complete the table
 231  * with information on each admissible feature (whether present or not).
 232  *
 233  * Return the composite bit-mask representing the features found.
 234  */
 235 static uint64_t parse_features(FeatureEntry feature_tbl[], const char input[]) {
 236   log_info(os, cpu)("Parse CPU features: %s\n", input);
 237 
 238 #ifdef ASSERT
 239   // Verify that hash value entries in the table are unique and ordered.
 240 
 241   uint32_t prev = 0;
 242 
 243   for (uint k = 0; feature_tbl[k].name != NULL; k++) {
 244     feature_tbl[k].seen = false;
 245 
 246     assert(feature_tbl[k].hash == uhash32(feature_tbl[k].name),
 247            "feature '%s' has mismatching hash 0x%08x (expected 0x%08x).\n",
 248            feature_tbl[k].name,
 249            feature_tbl[k].hash,
 250            uhash32(feature_tbl[k].name));
 251 
 252     assert(prev < feature_tbl[k].hash,
 253            "feature '%s' has invalid hash 0x%08x (previous is 0x%08x).\n",
 254            feature_tbl[k].name,
 255            feature_tbl[k].hash,
 256            prev);
 257 
 258     prev = feature_tbl[k].hash;
 259   }
 260 #endif
 261   // Identify features from the input, consisting of a string with features
 262   // separated by commas (or whitespace), e.g. "flush,muldiv,v9,mul32,div32,
 263   // v8plus,popc,vis".
 264 
 265   uint32_t hv = 0;
 266   const char* ch1p = &input[0];
 267   uint i = 0;
 268 
 269   do {
 270     char ch = input[i];
 271 
 272     if (isalnum(ch) || ch == '_') {
 273       hv += (ch - 32u);
 274     }
 275     else if (isspace(ch) || ch == ',' || ch == '\0') { // end-of-token
 276       if (ch1p < &input[i]) {
 277         update_table(feature_tbl, hv, ch1p, &input[i]);
 278       }
 279       ch1p = &input[i + 1]; hv = 0;
 280     } else {
 281       // Handle non-accepted input robustly.
 282       log_info(os, cpu)("Bad token in feature string: '%c' (0x%02x).\n", ch, ch);
 283       ch1p = &input[i + 1]; hv = 0;
 284     }
 285   }
 286   while (input[i++] != '\0');
 287 
 288   // Compute actual bit-mask representation.
 289 
 290   uint64_t mask = 0;
 291 
 292   for (uint k = 0; feature_tbl[k].name != NULL; k++) {
 293     mask |= feature_tbl[k].seen ? feature_tbl[k].mask : 0;
 294   }
 295 
 296   return mask;
 297 }
 298 
 299 static uint32_t uhash32(const char name[]) {
 300   uint32_t hv = 0;
 301 
 302   for (uint i = 0; name[i] != '\0'; i++) {
 303     hv += (name[i] - 32u);
 304   }
 305 
 306   return hv;
 307 }
 308 
 309 static bool verify_match(const char name[], const char* ch1p, const char* endp);
 310 
 311 static void update_table(FeatureEntry feature_tbl[], uint32_t hv, const char* ch1p, const char* endp) {
 312   assert(ch1p < endp, "at least one character");
 313 
 314   // Look for a hash value in the table. Since this table is a small one (and
 315   // is expected to stay small), we use a simple linear search (iff the table
 316   // grows large, we may consider to adopt a binary ditto, or a perfect hash).
 317 
 318   for (uint k = 0; feature_tbl[k].name != NULL; k++) {
 319     uint32_t hash = feature_tbl[k].hash;
 320 
 321     if (hash < hv) continue;
 322 
 323     if (hash == hv) {
 324       const char* name = feature_tbl[k].name;
 325 
 326       if (verify_match(name, ch1p, endp)) {
 327         feature_tbl[k].seen = true;
 328         break;
 329       }
 330     }
 331 
 332     // Either a non-matching feature (when hash == hv) or hash > hv. In either
 333     // case we break out of the loop and terminate the search (note that the
 334     // table is assumed to be uniquely sorted on the hash).
 335 
 336     break;
 337   }
 338 }
 339 
 340 static bool verify_match(const char name[], const char* ch1p, const char* endp) {
 341   size_t len = strlen(name);
 342 
 343   if (len != static_cast<size_t>(endp - ch1p)) {
 344     return false;
 345   }
 346 
 347   for (uint i = 0; ch1p + i < endp; i++) {
 348     if (name[i] != ch1p[i]) return false;
 349   }
 350 
 351   return true;
 352 }