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 40 extern "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) 43 extern "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 56 class 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; 190 public: 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 226 extern "C" static int PICL_visit_cpu_helper(picl_nodehdl_t nodeh, void *result) { 227 return PICL::visit_cpu(nodeh, result); 228 } 229 230 template<typename FuncType> 231 bool PICL::bind(FuncType& func, const char* name) { 232 func = reinterpret_cast<FuncType>(dlsym(_dl_handle, name)); 233 return func != NULL; 234 } 235 236 bool 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 247 bool 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 260 void 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 281 class Sysinfo { 282 char* _string; 283 public: 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 323 class Sysconf { 324 int _value; 325 public: 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 346 // Hardware capability bits that appeared after Solaris 11.1 347 #ifndef AV_SPARC_FMAF 348 #define AV_SPARC_FMAF 0x00000100 /* Fused Multiply-Add */ 349 #endif 350 #ifndef AV2_SPARC_SPARC5 351 #define AV2_SPARC_SPARC5 0x00000008 /* The 29 new fp and sub instructions */ 352 #endif 353 354 int VM_Version::platform_features(int features) { 355 356 // Check 32-bit architecture. 357 if (Sysinfo(SI_ARCHITECTURE_32).match("sparc")) { 358 features |= v8_instructions_m; 359 } 360 361 // Check 64-bit architecture. 362 if (Sysinfo(SI_ARCHITECTURE_64).match("sparcv9")) { 363 features |= generic_v9_m; 364 } 365 366 // Extract valid instruction set extensions. 367 uint_t avs[AV_HW2_IDX + 1]; 368 uint_t avn = getisax(avs, ARRAY_SIZE(avs)); 369 370 log_info(os, cpu)("getisax(2) returned %d words:", avn); 371 for (int i = 0; i < avn; i++) { 372 log_info(os, cpu)(" word %d: " PTR32_FORMAT, i, avs[i]); 373 } 374 375 uint_t av1 = avs[AV_HW1_IDX]; 376 if (av1 & AV_SPARC_MUL32) features |= hardware_mul32_m; 377 if (av1 & AV_SPARC_DIV32) features |= hardware_div32_m; 378 if (av1 & AV_SPARC_FSMULD) features |= hardware_fsmuld_m; 379 if (av1 & AV_SPARC_V8PLUS) features |= v9_instructions_m; 380 if (av1 & AV_SPARC_POPC) features |= hardware_popc_m; 381 if (av1 & AV_SPARC_VIS) features |= vis1_instructions_m; 382 if (av1 & AV_SPARC_VIS2) features |= vis2_instructions_m; 383 if (av1 & AV_SPARC_ASI_BLK_INIT) features |= blk_init_instructions_m; 384 if (av1 & AV_SPARC_FMAF) features |= fmaf_instructions_m; 385 if (av1 & AV_SPARC_VIS3) features |= vis3_instructions_m; 386 if (av1 & AV_SPARC_CBCOND) features |= cbcond_instructions_m; 387 if (av1 & AV_SPARC_CRC32C) features |= crc32c_instruction_m; 388 if (av1 & AV_SPARC_AES) features |= aes_instructions_m; 389 if (av1 & AV_SPARC_SHA1) features |= sha1_instruction_m; 390 if (av1 & AV_SPARC_SHA256) features |= sha256_instruction_m; 391 if (av1 & AV_SPARC_SHA512) features |= sha512_instruction_m; 392 393 if (avn > AV_HW2_IDX) { 394 uint_t av2 = avs[AV_HW2_IDX]; 395 if (av2 & AV2_SPARC_SPARC5) features |= sparc5_instructions_m; 396 } 397 398 // Determine the machine type. 399 if (Sysinfo(SI_MACHINE).match("sun4v")) { 400 features |= sun4v_m; 401 } 402 403 // If SI_CPUBRAND works, that means Solaris 12 API to get the cache line sizes 404 // is available to us as well 405 Sysinfo cpu_info(SI_CPUBRAND); 406 bool use_solaris_12_api = cpu_info.valid(); 407 const char* impl = "unknown"; 408 int impl_m = 0; 409 if (use_solaris_12_api) { 410 impl = cpu_info.value(); 411 log_info(os, cpu)("Parsing CPU implementation from %s", impl); 412 impl_m = parse_features(impl); 413 } else { 414 // Otherwise use kstat to determine the machine type. 415 kstat_ctl_t* kc = kstat_open(); 416 if (kc != NULL) { 417 kstat_t* ksp = kstat_lookup(kc, (char*)"cpu_info", -1, NULL); 418 if (ksp != NULL) { 419 if (kstat_read(kc, ksp, NULL) != -1 && ksp->ks_data != NULL) { 420 kstat_named_t* knm = (kstat_named_t *)ksp->ks_data; 421 for (int i = 0; i < ksp->ks_ndata; i++) { 422 if (strcmp((const char*)&(knm[i].name), "implementation") == 0) { 423 impl = KSTAT_NAMED_STR_PTR(&knm[i]); 424 log_info(os, cpu)("Parsing CPU implementation from %s", impl); 425 impl_m = parse_features(impl); 426 break; 427 } 428 } 429 } 430 } 431 kstat_close(kc); 432 } 433 } 434 assert(impl_m != 0, "Unknown CPU implementation %s", impl); 435 features |= impl_m; 436 437 bool is_sun4v = (features & sun4v_m) != 0; 438 if (use_solaris_12_api && is_sun4v) { 439 // If Solaris 12 API is supported and it's sun4v use sysconf() to get the cache line sizes 440 Sysconf l1_dcache_line_size(_SC_DCACHE_LINESZ); 441 if (l1_dcache_line_size.valid()) { 442 _L1_data_cache_line_size = l1_dcache_line_size.value(); 443 } 444 445 Sysconf l2_dcache_line_size(_SC_L2CACHE_LINESZ); 446 if (l2_dcache_line_size.valid()) { 447 _L2_data_cache_line_size = l2_dcache_line_size.value(); 448 } 449 } else { 450 // Otherwise figure out the cache line sizes using PICL 451 bool is_fujitsu = (features & sparc64_family_m) != 0; 452 PICL picl(is_fujitsu, is_sun4v); 453 _L1_data_cache_line_size = picl.L1_data_cache_line_size(); 454 _L2_data_cache_line_size = picl.L2_data_cache_line_size(); 455 } 456 return features; 457 }