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/systeminfo.h> 34 #include <picl.h> 35 #include <dlfcn.h> 36 #include <link.h> 37 38 extern "C" static int PICL_visit_cpu_helper(picl_nodehdl_t nodeh, void *result); 39 40 // Functions from the library we need (signatures should match those in picl.h) 41 extern "C" { 42 typedef int (*picl_initialize_func_t)(void); 43 typedef int (*picl_shutdown_func_t)(void); 44 typedef int (*picl_get_root_func_t)(picl_nodehdl_t *nodehandle); 45 typedef int (*picl_walk_tree_by_class_func_t)(picl_nodehdl_t rooth, 46 const char *classname, void *c_args, 47 int (*callback_fn)(picl_nodehdl_t hdl, void *args)); 48 typedef int (*picl_get_prop_by_name_func_t)(picl_nodehdl_t nodeh, const char *nm, 49 picl_prophdl_t *ph); 50 typedef int (*picl_get_propval_func_t)(picl_prophdl_t proph, void *valbuf, size_t sz); 51 typedef int (*picl_get_propinfo_func_t)(picl_prophdl_t proph, picl_propinfo_t *pi); 52 } 53 54 class PICL { 55 // Pointers to functions in the library 56 picl_initialize_func_t _picl_initialize; 57 picl_shutdown_func_t _picl_shutdown; 58 picl_get_root_func_t _picl_get_root; 59 picl_walk_tree_by_class_func_t _picl_walk_tree_by_class; 60 picl_get_prop_by_name_func_t _picl_get_prop_by_name; 61 picl_get_propval_func_t _picl_get_propval; 62 picl_get_propinfo_func_t _picl_get_propinfo; 63 // Handle to the library that is returned by dlopen 64 void *_dl_handle; 65 66 bool open_library(); 67 void close_library(); 68 69 template<typename FuncType> bool bind(FuncType& func, const char* name); 70 bool bind_library_functions(); 71 72 // Get a value of the integer property. The value in the tree can be either 32 or 64 bit 73 // depending on the platform. The result is converted to int. 74 int get_int_property(picl_nodehdl_t nodeh, const char* name, int* result) { 75 picl_propinfo_t pinfo; 76 picl_prophdl_t proph; 77 if (_picl_get_prop_by_name(nodeh, name, &proph) != PICL_SUCCESS || 78 _picl_get_propinfo(proph, &pinfo) != PICL_SUCCESS) { 79 return PICL_FAILURE; 80 } 81 82 if (pinfo.type != PICL_PTYPE_INT && pinfo.type != PICL_PTYPE_UNSIGNED_INT) { 83 assert(false, "Invalid property type"); 84 return PICL_FAILURE; 85 } 86 if (pinfo.size == sizeof(int64_t)) { 87 int64_t val; 88 if (_picl_get_propval(proph, &val, sizeof(int64_t)) != PICL_SUCCESS) { 89 return PICL_FAILURE; 90 } 91 *result = static_cast<int>(val); 92 } else if (pinfo.size == sizeof(int32_t)) { 93 int32_t val; 94 if (_picl_get_propval(proph, &val, sizeof(int32_t)) != PICL_SUCCESS) { 95 return PICL_FAILURE; 96 } 97 *result = static_cast<int>(val); 98 } else { 99 assert(false, "Unexpected integer property size"); 100 return PICL_FAILURE; 101 } 102 return PICL_SUCCESS; 103 } 104 105 // Visitor and a state machine that visits integer properties and verifies that the 106 // values are the same. Stores the unique value observed. 107 class UniqueValueVisitor { 108 PICL *_picl; 109 enum { 110 INITIAL, // Start state, no assignments happened 111 ASSIGNED, // Assigned a value 112 INCONSISTENT // Inconsistent value seen 113 } _state; 114 int _value; 115 public: 116 UniqueValueVisitor(PICL* picl) : _picl(picl), _state(INITIAL) { } 117 int value() { 118 assert(_state == ASSIGNED, "Precondition"); 119 return _value; 120 } 121 void set_value(int value) { 122 assert(_state == INITIAL, "Precondition"); 123 _value = value; 124 _state = ASSIGNED; 125 } 126 bool is_initial() { return _state == INITIAL; } 127 bool is_assigned() { return _state == ASSIGNED; } 128 bool is_inconsistent() { return _state == INCONSISTENT; } 129 void set_inconsistent() { _state = INCONSISTENT; } 130 131 bool visit(picl_nodehdl_t nodeh, const char* name) { 132 assert(!is_inconsistent(), "Precondition"); 133 int curr; 134 if (_picl->get_int_property(nodeh, name, &curr) == PICL_SUCCESS) { 135 if (!is_assigned()) { // first iteration 136 set_value(curr); 137 } else if (curr != value()) { // following iterations 138 set_inconsistent(); 139 } 140 return true; 141 } 142 return false; 143 } 144 }; 145 146 class CPUVisitor { 147 UniqueValueVisitor _l1_visitor; 148 UniqueValueVisitor _l2_visitor; 149 int _limit; // number of times visit() can be run 150 public: 151 CPUVisitor(PICL *picl, int limit) : _l1_visitor(picl), _l2_visitor(picl), _limit(limit) {} 152 static int visit(picl_nodehdl_t nodeh, void *arg) { 153 CPUVisitor *cpu_visitor = static_cast<CPUVisitor*>(arg); 154 UniqueValueVisitor* l1_visitor = cpu_visitor->l1_visitor(); 155 UniqueValueVisitor* l2_visitor = cpu_visitor->l2_visitor(); 156 if (!l1_visitor->is_inconsistent()) { 157 l1_visitor->visit(nodeh, "l1-dcache-line-size"); 158 } 159 static const char* l2_data_cache_line_property_name = NULL; 160 // On the first visit determine the name of the l2 cache line size property and memoize it. 161 if (l2_data_cache_line_property_name == NULL) { 162 assert(!l2_visitor->is_inconsistent(), "First iteration cannot be inconsistent"); 163 l2_data_cache_line_property_name = "l2-cache-line-size"; 164 if (!l2_visitor->visit(nodeh, l2_data_cache_line_property_name)) { 165 l2_data_cache_line_property_name = "l2-dcache-line-size"; 166 l2_visitor->visit(nodeh, l2_data_cache_line_property_name); 167 } 168 } else { 169 if (!l2_visitor->is_inconsistent()) { 170 l2_visitor->visit(nodeh, l2_data_cache_line_property_name); 171 } 172 } 173 174 if (l1_visitor->is_inconsistent() && l2_visitor->is_inconsistent()) { 175 return PICL_WALK_TERMINATE; 176 } 177 cpu_visitor->_limit--; 178 if (cpu_visitor->_limit <= 0) { 179 return PICL_WALK_TERMINATE; 180 } 181 return PICL_WALK_CONTINUE; 182 } 183 UniqueValueVisitor* l1_visitor() { return &_l1_visitor; } 184 UniqueValueVisitor* l2_visitor() { return &_l2_visitor; } 185 }; 186 int _L1_data_cache_line_size; 187 int _L2_data_cache_line_size; 188 public: 189 static int visit_cpu(picl_nodehdl_t nodeh, void *state) { 190 return CPUVisitor::visit(nodeh, state); 191 } 192 193 PICL(bool is_fujitsu, bool is_sun4v) : _L1_data_cache_line_size(0), _L2_data_cache_line_size(0), _dl_handle(NULL) { 194 if (!open_library()) { 195 return; 196 } 197 if (_picl_initialize() == PICL_SUCCESS) { 198 picl_nodehdl_t rooth; 199 if (_picl_get_root(&rooth) == PICL_SUCCESS) { 200 const char* cpu_class = "cpu"; 201 // If it's a Fujitsu machine, it's a "core" 202 if (is_fujitsu) { 203 cpu_class = "core"; 204 } 205 CPUVisitor cpu_visitor(this, (is_sun4v && !is_fujitsu) ? 1 : os::processor_count()); 206 _picl_walk_tree_by_class(rooth, cpu_class, &cpu_visitor, PICL_visit_cpu_helper); 207 if (cpu_visitor.l1_visitor()->is_assigned()) { // Is there a value? 208 _L1_data_cache_line_size = cpu_visitor.l1_visitor()->value(); 209 } 210 if (cpu_visitor.l2_visitor()->is_assigned()) { 211 _L2_data_cache_line_size = cpu_visitor.l2_visitor()->value(); 212 } 213 } 214 _picl_shutdown(); 215 } 216 close_library(); 217 } 218 219 unsigned int L1_data_cache_line_size() const { return _L1_data_cache_line_size; } 220 unsigned int L2_data_cache_line_size() const { return _L2_data_cache_line_size; } 221 }; 222 223 224 extern "C" static int PICL_visit_cpu_helper(picl_nodehdl_t nodeh, void *result) { 225 return PICL::visit_cpu(nodeh, result); 226 } 227 228 template<typename FuncType> 229 bool PICL::bind(FuncType& func, const char* name) { 230 func = reinterpret_cast<FuncType>(dlsym(_dl_handle, name)); 231 return func != NULL; 232 } 233 234 bool PICL::bind_library_functions() { 235 assert(_dl_handle != NULL, "library should be open"); 236 return bind(_picl_initialize, "picl_initialize" ) && 237 bind(_picl_shutdown, "picl_shutdown" ) && 238 bind(_picl_get_root, "picl_get_root" ) && 239 bind(_picl_walk_tree_by_class, "picl_walk_tree_by_class") && 240 bind(_picl_get_prop_by_name, "picl_get_prop_by_name" ) && 241 bind(_picl_get_propval, "picl_get_propval" ) && 242 bind(_picl_get_propinfo, "picl_get_propinfo" ); 243 } 244 245 bool PICL::open_library() { 246 _dl_handle = dlopen("libpicl.so.1", RTLD_LAZY); 247 if (_dl_handle == NULL) { 248 return false; 249 } 250 if (!bind_library_functions()) { 251 assert(false, "unexpected PICL API change"); 252 close_library(); 253 return false; 254 } 255 return true; 256 } 257 258 void PICL::close_library() { 259 assert(_dl_handle != NULL, "library should be open"); 260 dlclose(_dl_handle); 261 _dl_handle = NULL; 262 } 263 264 class Sysinfo { 265 char* _string; 266 public: 267 Sysinfo(int si) : _string(NULL) { 268 char tmp; 269 size_t bufsize = sysinfo(si, &tmp, 1); 270 271 if (bufsize != -1) { 272 char* buf = (char*) os::malloc(bufsize, mtInternal); 273 if (buf != NULL) { 274 if (sysinfo(si, buf, bufsize) == bufsize) { 275 _string = buf; 276 } else { 277 os::free(buf); 278 } 279 } 280 } 281 } 282 283 ~Sysinfo() { 284 if (_string != NULL) { 285 os::free(_string); 286 } 287 } 288 289 const char* value() const { 290 return _string; 291 } 292 293 bool valid() const { 294 return _string != NULL; 295 } 296 297 bool match(const char* s) const { 298 return valid() ? strcmp(_string, s) == 0 : false; 299 } 300 301 bool match_substring(const char* s) const { 302 return valid() ? strstr(_string, s) != NULL : false; 303 } 304 }; 305 306 class Sysconf { 307 int _value; 308 public: 309 Sysconf(int sc) : _value(-1) { 310 _value = sysconf(sc); 311 } 312 bool valid() const { 313 return _value != -1; 314 } 315 int value() const { 316 return _value; 317 } 318 }; 319 320 321 #ifndef _SC_DCACHE_LINESZ 322 #define _SC_DCACHE_LINESZ 508 /* Data cache line size */ 323 #endif 324 325 #ifndef _SC_L2CACHE_LINESZ 326 #define _SC_L2CACHE_LINESZ 527 /* Size of L2 cache line */ 327 #endif 328 329 void VM_Version::platform_features() { 330 uint64_t features = ISA_v9_msk; // Basic SPARC-V9 required (V8 not supported). 331 332 assert(Sysinfo(SI_ARCHITECTURE_64).match("sparcv9"), "must be"); 333 334 // Extract valid instruction set extensions. 335 uint32_t avs[AV_HW2_IDX + 1]; 336 uint_t avn = getisax(avs, AV_HW2_IDX + 1); 337 assert(avn <= 2, "should return two or less av's"); 338 339 log_info(os, cpu)("getisax(2) returned %d words:", avn); 340 for (int i = 0; i < avn; i++) { 341 log_info(os, cpu)(" word %d: " PTR32_FORMAT, i, avs[i]); 342 } 343 344 uint32_t av = avs[AV_HW1_IDX]; 345 346 // Obsolete and 32b legacy mode capabilites NOT probed here, despite being 347 // set by Solaris 11.4 (onward) also on V9; AV_SPARC_MUL32, AV_SPARC_DIV32 348 // and AV_SPARC_FSMULD (and AV_SPARC_V8PLUS). 349 350 if (av & AV_SPARC_POPC) features |= ISA_popc_msk; 351 if (av & AV_SPARC_VIS) features |= ISA_vis1_msk; 352 if (av & AV_SPARC_VIS2) features |= ISA_vis2_msk; 353 354 // Hardware capability defines introduced after Solaris 11.1: 355 356 #ifndef AV_SPARC_FMAF 357 #define AV_SPARC_FMAF 0x00000100 // Fused Multiply-Add 358 #endif 359 360 if (av & AV_SPARC_ASI_BLK_INIT) features |= ISA_blk_init_msk; 361 if (av & AV_SPARC_FMAF) features |= ISA_fmaf_msk; 362 if (av & AV_SPARC_VIS3) features |= ISA_vis3_msk; 363 if (av & AV_SPARC_HPC) features |= ISA_hpc_msk; 364 if (av & AV_SPARC_IMA) features |= ISA_ima_msk; 365 if (av & AV_SPARC_AES) features |= ISA_aes_msk; 366 if (av & AV_SPARC_DES) features |= ISA_des_msk; 367 if (av & AV_SPARC_KASUMI) features |= ISA_kasumi_msk; 368 if (av & AV_SPARC_CAMELLIA) features |= ISA_camellia_msk; 369 if (av & AV_SPARC_MD5) features |= ISA_md5_msk; 370 if (av & AV_SPARC_SHA1) features |= ISA_sha1_msk; 371 if (av & AV_SPARC_SHA256) features |= ISA_sha256_msk; 372 if (av & AV_SPARC_SHA512) features |= ISA_sha512_msk; 373 if (av & AV_SPARC_MPMUL) features |= ISA_mpmul_msk; 374 if (av & AV_SPARC_MONT) features |= ISA_mont_msk; 375 if (av & AV_SPARC_PAUSE) features |= ISA_pause_msk; 376 if (av & AV_SPARC_CBCOND) features |= ISA_cbcond_msk; 377 if (av & AV_SPARC_CRC32C) features |= ISA_crc32c_msk; 378 379 #ifndef AV2_SPARC_FJATHPLUS 380 #define AV2_SPARC_FJATHPLUS 0x00000001 // Fujitsu Athena+ insns 381 #endif 382 #ifndef AV2_SPARC_VIS3B 383 #define AV2_SPARC_VIS3B 0x00000002 // VIS3 present on multiple chips 384 #endif 385 #ifndef AV2_SPARC_ADI 386 #define AV2_SPARC_ADI 0x00000004 // Application Data Integrity 387 #endif 388 #ifndef AV2_SPARC_SPARC5 389 #define AV2_SPARC_SPARC5 0x00000008 // The 29 new fp and sub instructions 390 #endif 391 #ifndef AV2_SPARC_MWAIT 392 #define AV2_SPARC_MWAIT 0x00000010 // mwait instruction and load/monitor ASIs 393 #endif 394 #ifndef AV2_SPARC_XMPMUL 395 #define AV2_SPARC_XMPMUL 0x00000020 // XOR multiple precision multiply 396 #endif 397 #ifndef AV2_SPARC_XMONT 398 #define AV2_SPARC_XMONT 0x00000040 // XOR Montgomery mult/sqr instructions 399 #endif 400 #ifndef AV2_SPARC_PAUSE_NSEC 401 #define AV2_SPARC_PAUSE_NSEC 0x00000080 // pause instruction with support for nsec timings 402 #endif 403 #ifndef AV2_SPARC_VAMASK 404 #define AV2_SPARC_VAMASK 0x00000100 // Virtual Address masking 405 #endif 406 407 #ifndef AV2_SPARC_SPARC6 408 #define AV2_SPARC_SPARC6 0x00000200 // REVB*, FPSLL*, RDENTROPY, LDM* and STM* 409 #endif 410 #ifndef AV2_SPARC_DICTUNP 411 #define AV2_SPARC_DICTUNP 0x00002000 // Dictionary unpack instruction 412 #endif 413 #ifndef AV2_SPARC_FPCMPSHL 414 #define AV2_SPARC_FPCMPSHL 0x00004000 // Partition compare with shifted result 415 #endif 416 #ifndef AV2_SPARC_RLE 417 #define AV2_SPARC_RLE 0x00008000 // Run-length encoded burst and length 418 #endif 419 #ifndef AV2_SPARC_SHA3 420 #define AV2_SPARC_SHA3 0x00010000 // SHA3 instructions 421 #endif 422 #ifndef AV2_SPARC_FJATHPLUS2 423 #define AV2_SPARC_FJATHPLUS2 0x00020000 // Fujitsu Athena++ insns 424 #endif 425 #ifndef AV2_SPARC_VIS3C 426 #define AV2_SPARC_VIS3C 0x00040000 // Subset of VIS3 insns provided by Athena++ 427 #endif 428 #ifndef AV2_SPARC_SPARC5B 429 #define AV2_SPARC_SPARC5B 0x00080000 // subset of SPARC5 insns (fpadd8, fpsub8) 430 #endif 431 #ifndef AV2_SPARC_MME 432 #define AV2_SPARC_MME 0x00100000 // Misaligned Mitigation Enable 433 #endif 434 435 if (avn > 1) { 436 uint32_t av2 = avs[AV_HW2_IDX]; 437 438 if (av2 & AV2_SPARC_FJATHPLUS) features |= ISA_fjathplus_msk; 439 if (av2 & AV2_SPARC_VIS3B) features |= ISA_vis3b_msk; 440 if (av2 & AV2_SPARC_ADI) features |= ISA_adi_msk; 441 if (av2 & AV2_SPARC_SPARC5) features |= ISA_sparc5_msk; 442 if (av2 & AV2_SPARC_MWAIT) features |= ISA_mwait_msk; 443 if (av2 & AV2_SPARC_XMPMUL) features |= ISA_xmpmul_msk; 444 if (av2 & AV2_SPARC_XMONT) features |= ISA_xmont_msk; 445 if (av2 & AV2_SPARC_PAUSE_NSEC) features |= ISA_pause_nsec_msk; 446 if (av2 & AV2_SPARC_VAMASK) features |= ISA_vamask_msk; 447 448 if (av2 & AV2_SPARC_SPARC6) features |= ISA_sparc6_msk; 449 if (av2 & AV2_SPARC_DICTUNP) features |= ISA_dictunp_msk; 450 if (av2 & AV2_SPARC_FPCMPSHL) features |= ISA_fpcmpshl_msk; 451 if (av2 & AV2_SPARC_RLE) features |= ISA_rle_msk; 452 if (av2 & AV2_SPARC_SHA3) features |= ISA_sha3_msk; 453 if (av2 & AV2_SPARC_FJATHPLUS2) features |= ISA_fjathplus2_msk; 454 if (av2 & AV2_SPARC_VIS3C) features |= ISA_vis3c_msk; 455 if (av2 & AV2_SPARC_SPARC5B) features |= ISA_sparc5b_msk; 456 if (av2 & AV2_SPARC_MME) features |= ISA_mme_msk; 457 } 458 459 _features = features; // ISA feature set completed, update state. 460 461 Sysinfo machine(SI_MACHINE); 462 463 bool is_sun4v = machine.match("sun4v"); // All Oracle SPARC + Fujitsu Athena+/++ 464 bool is_sun4u = machine.match("sun4u"); // All other Fujitsu 465 466 // Handle Athena+/++ conservatively (simply because we are lacking info.). 467 468 bool an_athena = has_athena_plus() || has_athena_plus2(); 469 bool do_sun4v = is_sun4v && !an_athena; 470 bool do_sun4u = is_sun4u || an_athena; 471 472 uint64_t synthetic = 0; 473 474 if (do_sun4v) { 475 // Indirect and direct branches are equally fast. 476 synthetic = CPU_fast_ind_br_msk; 477 // Fast IDIV, BIS and LD available on Niagara Plus. 478 if (has_vis2()) { 479 synthetic |= (CPU_fast_idiv_msk | CPU_fast_ld_msk); 480 // ...on Core C4 however, we prefer not to use BIS. 481 if (!has_sparc5()) { 482 synthetic |= CPU_fast_bis_msk; 483 } 484 } 485 // SPARC Core C3 supports fast RDPC and block zeroing. 486 if (has_ima()) { 487 synthetic |= (CPU_fast_rdpc_msk | CPU_blk_zeroing_msk); 488 } 489 // SPARC Core C3 and C4 have slow CMOVE. 490 if (!has_ima()) { 491 synthetic |= CPU_fast_cmove_msk; 492 } 493 } else if (do_sun4u) { 494 // SPARC64 only have fast IDIV and RDPC. 495 synthetic |= (CPU_fast_idiv_msk | CPU_fast_rdpc_msk); 496 } else { 497 log_info(os, cpu)("Unable to derive CPU features: %s", machine.value()); 498 } 499 500 _features += synthetic; // Including CPU derived/synthetic features. 501 502 Sysconf l1_dcache_line_size(_SC_DCACHE_LINESZ); 503 Sysconf l2_dcache_line_size(_SC_L2CACHE_LINESZ); 504 505 // Require both Sysconf requests to be valid or use fall-back. 506 507 if (l1_dcache_line_size.valid() && 508 l2_dcache_line_size.valid()) { 509 _L1_data_cache_line_size = l1_dcache_line_size.value(); 510 _L2_data_cache_line_size = l2_dcache_line_size.value(); 511 } else { 512 // Otherwise figure out the cache line sizes using PICL. 513 PICL picl(is_sun4u, is_sun4v); 514 _L1_data_cache_line_size = picl.L1_data_cache_line_size(); 515 _L2_data_cache_line_size = picl.L2_data_cache_line_size(); 516 } 517 }