vm_version_solaris_sparc.cpp revision 10835:a6b1b83401c7
1/*
2 * Copyright (c) 2006, 2016, 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 "precompiled.hpp"
26#include "logging/log.hpp"
27#include "memory/allocation.hpp"
28#include "memory/allocation.inline.hpp"
29#include "runtime/os.hpp"
30#include "vm_version_sparc.hpp"
31
32#include <sys/auxv.h>
33#include <sys/auxv_SPARC.h>
34#include <sys/systeminfo.h>
35#include <kstat.h>
36#include <picl.h>
37#include <dlfcn.h>
38#include <link.h>
39
40extern "C" static int PICL_visit_cpu_helper(picl_nodehdl_t nodeh, void *result);
41
42// Functions from the library we need (signatures should match those in picl.h)
43extern "C" {
44  typedef int (*picl_initialize_func_t)(void);
45  typedef int (*picl_shutdown_func_t)(void);
46  typedef int (*picl_get_root_func_t)(picl_nodehdl_t *nodehandle);
47  typedef int (*picl_walk_tree_by_class_func_t)(picl_nodehdl_t rooth,
48      const char *classname, void *c_args,
49      int (*callback_fn)(picl_nodehdl_t hdl, void *args));
50  typedef int (*picl_get_prop_by_name_func_t)(picl_nodehdl_t nodeh, const char *nm,
51      picl_prophdl_t *ph);
52  typedef int (*picl_get_propval_func_t)(picl_prophdl_t proph, void *valbuf, size_t sz);
53  typedef int (*picl_get_propinfo_func_t)(picl_prophdl_t proph, picl_propinfo_t *pi);
54}
55
56class PICL {
57  // Pointers to functions in the library
58  picl_initialize_func_t _picl_initialize;
59  picl_shutdown_func_t _picl_shutdown;
60  picl_get_root_func_t _picl_get_root;
61  picl_walk_tree_by_class_func_t _picl_walk_tree_by_class;
62  picl_get_prop_by_name_func_t _picl_get_prop_by_name;
63  picl_get_propval_func_t _picl_get_propval;
64  picl_get_propinfo_func_t _picl_get_propinfo;
65  // Handle to the library that is returned by dlopen
66  void *_dl_handle;
67
68  bool open_library();
69  void close_library();
70
71  template<typename FuncType> bool bind(FuncType& func, const char* name);
72  bool bind_library_functions();
73
74  // Get a value of the integer property. The value in the tree can be either 32 or 64 bit
75  // depending on the platform. The result is converted to int.
76  int get_int_property(picl_nodehdl_t nodeh, const char* name, int* result) {
77    picl_propinfo_t pinfo;
78    picl_prophdl_t proph;
79    if (_picl_get_prop_by_name(nodeh, name, &proph) != PICL_SUCCESS ||
80        _picl_get_propinfo(proph, &pinfo) != PICL_SUCCESS) {
81      return PICL_FAILURE;
82    }
83
84    if (pinfo.type != PICL_PTYPE_INT && pinfo.type != PICL_PTYPE_UNSIGNED_INT) {
85      assert(false, "Invalid property type");
86      return PICL_FAILURE;
87    }
88    if (pinfo.size == sizeof(int64_t)) {
89      int64_t val;
90      if (_picl_get_propval(proph, &val, sizeof(int64_t)) != PICL_SUCCESS) {
91        return PICL_FAILURE;
92      }
93      *result = static_cast<int>(val);
94    } else if (pinfo.size == sizeof(int32_t)) {
95      int32_t val;
96      if (_picl_get_propval(proph, &val, sizeof(int32_t)) != PICL_SUCCESS) {
97        return PICL_FAILURE;
98      }
99      *result = static_cast<int>(val);
100    } else {
101      assert(false, "Unexpected integer property size");
102      return PICL_FAILURE;
103    }
104    return PICL_SUCCESS;
105  }
106
107  // Visitor and a state machine that visits integer properties and verifies that the
108  // values are the same. Stores the unique value observed.
109  class UniqueValueVisitor {
110    PICL *_picl;
111    enum {
112      INITIAL,        // Start state, no assignments happened
113      ASSIGNED,       // Assigned a value
114      INCONSISTENT    // Inconsistent value seen
115    } _state;
116    int _value;
117  public:
118    UniqueValueVisitor(PICL* picl) : _picl(picl), _state(INITIAL) { }
119    int value() {
120      assert(_state == ASSIGNED, "Precondition");
121      return _value;
122    }
123    void set_value(int value) {
124      assert(_state == INITIAL, "Precondition");
125      _value = value;
126      _state = ASSIGNED;
127    }
128    bool is_initial()       { return _state == INITIAL;      }
129    bool is_assigned()      { return _state == ASSIGNED;     }
130    bool is_inconsistent()  { return _state == INCONSISTENT; }
131    void set_inconsistent() { _state = INCONSISTENT;         }
132
133    bool visit(picl_nodehdl_t nodeh, const char* name) {
134      assert(!is_inconsistent(), "Precondition");
135      int curr;
136      if (_picl->get_int_property(nodeh, name, &curr) == PICL_SUCCESS) {
137        if (!is_assigned()) { // first iteration
138          set_value(curr);
139        } else if (curr != value()) { // following iterations
140          set_inconsistent();
141        }
142        return true;
143      }
144      return false;
145    }
146  };
147
148  class CPUVisitor {
149    UniqueValueVisitor _l1_visitor;
150    UniqueValueVisitor _l2_visitor;
151    int _limit; // number of times visit() can be run
152  public:
153    CPUVisitor(PICL *picl, int limit) : _l1_visitor(picl), _l2_visitor(picl), _limit(limit) {}
154    static int visit(picl_nodehdl_t nodeh, void *arg) {
155      CPUVisitor *cpu_visitor = static_cast<CPUVisitor*>(arg);
156      UniqueValueVisitor* l1_visitor = cpu_visitor->l1_visitor();
157      UniqueValueVisitor* l2_visitor = cpu_visitor->l2_visitor();
158      if (!l1_visitor->is_inconsistent()) {
159        l1_visitor->visit(nodeh, "l1-dcache-line-size");
160      }
161      static const char* l2_data_cache_line_property_name = NULL;
162      // On the first visit determine the name of the l2 cache line size property and memoize it.
163      if (l2_data_cache_line_property_name == NULL) {
164        assert(!l2_visitor->is_inconsistent(), "First iteration cannot be inconsistent");
165        l2_data_cache_line_property_name = "l2-cache-line-size";
166        if (!l2_visitor->visit(nodeh, l2_data_cache_line_property_name)) {
167          l2_data_cache_line_property_name = "l2-dcache-line-size";
168          l2_visitor->visit(nodeh, l2_data_cache_line_property_name);
169        }
170      } else {
171        if (!l2_visitor->is_inconsistent()) {
172          l2_visitor->visit(nodeh, l2_data_cache_line_property_name);
173        }
174      }
175
176      if (l1_visitor->is_inconsistent() && l2_visitor->is_inconsistent()) {
177        return PICL_WALK_TERMINATE;
178      }
179      cpu_visitor->_limit--;
180      if (cpu_visitor->_limit <= 0) {
181        return PICL_WALK_TERMINATE;
182      }
183      return PICL_WALK_CONTINUE;
184    }
185    UniqueValueVisitor* l1_visitor() { return &_l1_visitor; }
186    UniqueValueVisitor* l2_visitor() { return &_l2_visitor; }
187  };
188  int _L1_data_cache_line_size;
189  int _L2_data_cache_line_size;
190public:
191  static int visit_cpu(picl_nodehdl_t nodeh, void *state) {
192    return CPUVisitor::visit(nodeh, state);
193  }
194
195  PICL(bool is_fujitsu, bool is_sun4v) : _L1_data_cache_line_size(0), _L2_data_cache_line_size(0), _dl_handle(NULL) {
196    if (!open_library()) {
197      return;
198    }
199    if (_picl_initialize() == PICL_SUCCESS) {
200      picl_nodehdl_t rooth;
201      if (_picl_get_root(&rooth) == PICL_SUCCESS) {
202        const char* cpu_class = "cpu";
203        // If it's a Fujitsu machine, it's a "core"
204        if (is_fujitsu) {
205          cpu_class = "core";
206        }
207        CPUVisitor cpu_visitor(this, (is_sun4v && !is_fujitsu) ? 1 : os::processor_count());
208        _picl_walk_tree_by_class(rooth, cpu_class, &cpu_visitor, PICL_visit_cpu_helper);
209        if (cpu_visitor.l1_visitor()->is_assigned()) { // Is there a value?
210          _L1_data_cache_line_size = cpu_visitor.l1_visitor()->value();
211        }
212        if (cpu_visitor.l2_visitor()->is_assigned()) {
213          _L2_data_cache_line_size = cpu_visitor.l2_visitor()->value();
214        }
215      }
216      _picl_shutdown();
217    }
218    close_library();
219  }
220
221  unsigned int L1_data_cache_line_size() const { return _L1_data_cache_line_size; }
222  unsigned int L2_data_cache_line_size() const { return _L2_data_cache_line_size; }
223};
224
225
226extern "C" static int PICL_visit_cpu_helper(picl_nodehdl_t nodeh, void *result) {
227  return PICL::visit_cpu(nodeh, result);
228}
229
230template<typename FuncType>
231bool PICL::bind(FuncType& func, const char* name) {
232  func = reinterpret_cast<FuncType>(dlsym(_dl_handle, name));
233  return func != NULL;
234}
235
236bool PICL::bind_library_functions() {
237  assert(_dl_handle != NULL, "library should be open");
238  return bind(_picl_initialize,         "picl_initialize"        ) &&
239         bind(_picl_shutdown,           "picl_shutdown"          ) &&
240         bind(_picl_get_root,           "picl_get_root"          ) &&
241         bind(_picl_walk_tree_by_class, "picl_walk_tree_by_class") &&
242         bind(_picl_get_prop_by_name,   "picl_get_prop_by_name"  ) &&
243         bind(_picl_get_propval,        "picl_get_propval"       ) &&
244         bind(_picl_get_propinfo,       "picl_get_propinfo"      );
245}
246
247bool PICL::open_library() {
248  _dl_handle = dlopen("libpicl.so.1", RTLD_LAZY);
249  if (_dl_handle == NULL) {
250    return false;
251  }
252  if (!bind_library_functions()) {
253    assert(false, "unexpected PICL API change");
254    close_library();
255    return false;
256  }
257  return true;
258}
259
260void PICL::close_library() {
261  assert(_dl_handle != NULL, "library should be open");
262  dlclose(_dl_handle);
263  _dl_handle = NULL;
264}
265
266// We need to keep these here as long as we have to build on Solaris
267// versions before 10.
268
269#ifndef SI_ARCHITECTURE_32
270#define SI_ARCHITECTURE_32      516     /* basic 32-bit SI_ARCHITECTURE */
271#endif
272
273#ifndef SI_ARCHITECTURE_64
274#define SI_ARCHITECTURE_64      517     /* basic 64-bit SI_ARCHITECTURE */
275#endif
276
277#ifndef SI_CPUBRAND
278#define SI_CPUBRAND             523     /* return cpu brand string */
279#endif
280
281class Sysinfo {
282  char* _string;
283public:
284  Sysinfo(int si) : _string(NULL) {
285    char   tmp;
286    size_t bufsize = sysinfo(si, &tmp, 1);
287
288    if (bufsize != -1) {
289      char* buf = (char*) os::malloc(bufsize, mtInternal);
290      if (buf != NULL) {
291        if (sysinfo(si, buf, bufsize) == bufsize) {
292          _string = buf;
293        } else {
294          os::free(buf);
295        }
296      }
297    }
298  }
299
300  ~Sysinfo() {
301    if (_string != NULL) {
302      os::free(_string);
303    }
304  }
305
306  const char* value() const {
307    return _string;
308  }
309
310  bool valid() const {
311    return _string != NULL;
312  }
313
314  bool match(const char* s) const {
315    return valid() ? strcmp(_string, s) == 0 : false;
316  }
317
318  bool match_substring(const char* s) const {
319    return valid() ? strstr(_string, s) != NULL : false;
320  }
321};
322
323class Sysconf {
324  int _value;
325public:
326  Sysconf(int sc) : _value(-1) {
327    _value = sysconf(sc);
328  }
329  bool valid() const {
330    return _value != -1;
331  }
332  int value() const {
333    return _value;
334  }
335};
336
337
338#ifndef _SC_DCACHE_LINESZ
339#define _SC_DCACHE_LINESZ       508     /* Data cache line size */
340#endif
341
342#ifndef _SC_L2CACHE_LINESZ
343#define _SC_L2CACHE_LINESZ      527     /* Size of L2 cache line */
344#endif
345
346int VM_Version::platform_features(int features) {
347  assert(os::Solaris::supports_getisax(), "getisax() must be available");
348
349  // Check 32-bit architecture.
350  if (Sysinfo(SI_ARCHITECTURE_32).match("sparc")) {
351    features |= v8_instructions_m;
352  }
353
354  // Check 64-bit architecture.
355  if (Sysinfo(SI_ARCHITECTURE_64).match("sparcv9")) {
356    features |= generic_v9_m;
357  }
358
359  // Extract valid instruction set extensions.
360  uint_t avs[2];
361  uint_t avn = os::Solaris::getisax(avs, 2);
362  assert(avn <= 2, "should return two or less av's");
363  uint_t av = avs[0];
364
365  log_info(os, cpu)("getisax(2) returned: " PTR32_FORMAT, av);
366  if (avn > 1) {
367    log_info(os, cpu)(" " PTR32_FORMAT, avs[1]);
368  }
369
370  if (av & AV_SPARC_MUL32)  features |= hardware_mul32_m;
371  if (av & AV_SPARC_DIV32)  features |= hardware_div32_m;
372  if (av & AV_SPARC_FSMULD) features |= hardware_fsmuld_m;
373  if (av & AV_SPARC_V8PLUS) features |= v9_instructions_m;
374  if (av & AV_SPARC_POPC)   features |= hardware_popc_m;
375  if (av & AV_SPARC_VIS)    features |= vis1_instructions_m;
376  if (av & AV_SPARC_VIS2)   features |= vis2_instructions_m;
377  if (avn > 1) {
378    uint_t av2 = avs[1];
379#ifndef AV2_SPARC_SPARC5
380#define AV2_SPARC_SPARC5 0x00000008 /* The 29 new fp and sub instructions */
381#endif
382    if (av2 & AV2_SPARC_SPARC5)       features |= sparc5_instructions_m;
383  }
384
385  // We only build on Solaris 10 and up, but some of the values below
386  // are not defined on all versions of Solaris 10, so we define them,
387  // if necessary.
388#ifndef AV_SPARC_ASI_BLK_INIT
389#define AV_SPARC_ASI_BLK_INIT 0x0080  /* ASI_BLK_INIT_xxx ASI */
390#endif
391  if (av & AV_SPARC_ASI_BLK_INIT) features |= blk_init_instructions_m;
392
393#ifndef AV_SPARC_FMAF
394#define AV_SPARC_FMAF 0x0100        /* Fused Multiply-Add */
395#endif
396  if (av & AV_SPARC_FMAF)         features |= fmaf_instructions_m;
397
398#ifndef AV_SPARC_FMAU
399#define AV_SPARC_FMAU    0x0200  /* Unfused Multiply-Add */
400#endif
401  if (av & AV_SPARC_FMAU)         features |= fmau_instructions_m;
402
403#ifndef AV_SPARC_VIS3
404#define AV_SPARC_VIS3    0x0400  /* VIS3 instruction set extensions */
405#endif
406  if (av & AV_SPARC_VIS3)         features |= vis3_instructions_m;
407
408#ifndef AV_SPARC_CBCOND
409#define AV_SPARC_CBCOND 0x10000000  /* compare and branch instrs supported */
410#endif
411  if (av & AV_SPARC_CBCOND)       features |= cbcond_instructions_m;
412
413#ifndef AV_SPARC_CRC32C
414#define AV_SPARC_CRC32C 0x20000000  /* crc32c instruction supported */
415#endif
416  if (av & AV_SPARC_CRC32C)       features |= crc32c_instruction_m;
417
418#ifndef AV_SPARC_AES
419#define AV_SPARC_AES 0x00020000  /* aes instrs supported */
420#endif
421  if (av & AV_SPARC_AES)       features |= aes_instructions_m;
422
423#ifndef AV_SPARC_SHA1
424#define AV_SPARC_SHA1   0x00400000  /* sha1 instruction supported */
425#endif
426  if (av & AV_SPARC_SHA1)         features |= sha1_instruction_m;
427
428#ifndef AV_SPARC_SHA256
429#define AV_SPARC_SHA256 0x00800000  /* sha256 instruction supported */
430#endif
431  if (av & AV_SPARC_SHA256)       features |= sha256_instruction_m;
432
433#ifndef AV_SPARC_SHA512
434#define AV_SPARC_SHA512 0x01000000  /* sha512 instruction supported */
435#endif
436  if (av & AV_SPARC_SHA512)       features |= sha512_instruction_m;
437
438  // Determine the machine type.
439  if (Sysinfo(SI_MACHINE).match("sun4v")) {
440    features |= sun4v_m;
441  }
442
443  bool use_solaris_12_api = false;
444  Sysinfo impl(SI_CPUBRAND);
445  if (impl.valid()) {
446    // If SI_CPUBRAND works, that means Solaris 12 API to get the cache line sizes
447    // is available to us as well
448    use_solaris_12_api = true;
449    features |= parse_features(impl.value());
450  } else {
451    // Otherwise use kstat to determine the machine type.
452    kstat_ctl_t* kc = kstat_open();
453    kstat_t* ksp = kstat_lookup(kc, (char*)"cpu_info", -1, NULL);
454    const char* implementation;
455    bool has_implementation = false;
456    if (ksp != NULL) {
457      if (kstat_read(kc, ksp, NULL) != -1 && ksp->ks_data != NULL) {
458        kstat_named_t* knm = (kstat_named_t *)ksp->ks_data;
459        for (int i = 0; i < ksp->ks_ndata; i++) {
460          if (strcmp((const char*)&(knm[i].name),"implementation") == 0) {
461            implementation = KSTAT_NAMED_STR_PTR(&knm[i]);
462            has_implementation = true;
463            log_info(os, cpu)("cpu_info.implementation: %s", implementation);
464            features |= parse_features(implementation);
465            break;
466          }
467        } // for(
468      }
469    }
470    assert(has_implementation, "unknown cpu info (changed kstat interface?)");
471    kstat_close(kc);
472  }
473
474  bool is_sun4v = (features & sun4v_m) != 0;
475  if (use_solaris_12_api && is_sun4v) {
476    // If Solaris 12 API is supported and it's sun4v use sysconf() to get the cache line sizes
477    Sysconf l1_dcache_line_size(_SC_DCACHE_LINESZ);
478    if (l1_dcache_line_size.valid()) {
479      _L1_data_cache_line_size =  l1_dcache_line_size.value();
480    }
481
482    Sysconf l2_dcache_line_size(_SC_L2CACHE_LINESZ);
483    if (l2_dcache_line_size.valid()) {
484      _L2_data_cache_line_size = l2_dcache_line_size.value();
485    }
486  } else {
487    // Otherwise figure out the cache line sizes using PICL
488    bool is_fujitsu = (features & sparc64_family_m) != 0;
489    PICL picl(is_fujitsu, is_sun4v);
490    _L1_data_cache_line_size = picl.L1_data_cache_line_size();
491    _L2_data_cache_line_size = picl.L2_data_cache_line_size();
492  }
493  return features;
494}
495