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 int 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 // If SI_CPUBRAND works, that means Solaris 12 API to get the cache line sizes 444 // is available to us as well 445 Sysinfo cpu_info(SI_CPUBRAND); 446 bool use_solaris_12_api = cpu_info.valid(); 447 const char* impl; 448 int impl_m = 0; 449 if (use_solaris_12_api) { 450 impl = cpu_info.value(); 451 log_info(os, cpu)("Parsing CPU implementation from %s", impl); 452 impl_m = parse_features(impl); 453 } else { 454 // Otherwise use kstat to determine the machine type. 455 kstat_ctl_t* kc = kstat_open(); 456 if (kc != NULL) { 457 kstat_t* ksp = kstat_lookup(kc, (char*)"cpu_info", -1, NULL); 458 if (ksp != NULL) { 459 if (kstat_read(kc, ksp, NULL) != -1 && ksp->ks_data != NULL) { 460 kstat_named_t* knm = (kstat_named_t *)ksp->ks_data; 461 for (int i = 0; i < ksp->ks_ndata; i++) { 462 if (strcmp((const char*)&(knm[i].name), "implementation") == 0) { 463 impl = KSTAT_NAMED_STR_PTR(&knm[i]); 464 log_info(os, cpu)("Parsing CPU implementation from %s", impl); 465 impl_m = parse_features(impl); 466 break; 467 } 468 } 469 } 470 } 471 kstat_close(kc); 472 } 473 } 474 assert(impl_m != 0, "Unknown CPU implementation %s", impl); 475 features |= impl_m; 476 477 bool is_sun4v = (features & sun4v_m) != 0; 478 if (use_solaris_12_api && is_sun4v) { 479 // If Solaris 12 API is supported and it's sun4v use sysconf() to get the cache line sizes 480 Sysconf l1_dcache_line_size(_SC_DCACHE_LINESZ); 481 if (l1_dcache_line_size.valid()) { 482 _L1_data_cache_line_size = l1_dcache_line_size.value(); 483 } 484 485 Sysconf l2_dcache_line_size(_SC_L2CACHE_LINESZ); 486 if (l2_dcache_line_size.valid()) { 487 _L2_data_cache_line_size = l2_dcache_line_size.value(); 488 } 489 } else { 490 // Otherwise figure out the cache line sizes using PICL 491 bool is_fujitsu = (features & sparc64_family_m) != 0; 492 PICL picl(is_fujitsu, is_sun4v); 493 _L1_data_cache_line_size = picl.L1_data_cache_line_size(); 494 _L2_data_cache_line_size = picl.L2_data_cache_line_size(); 495 } 496 return features; 497 }