1 /* 2 * Copyright (c) 2006, 2014, 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 "memory/allocation.hpp" 27 #include "memory/allocation.inline.hpp" 28 #include "runtime/os.hpp" 29 #include "vm_version_sparc.hpp" 30 31 #include <sys/auxv.h> 32 #include <sys/auxv_SPARC.h> 33 #include <sys/systeminfo.h> 34 #include <kstat.h> 35 #include <picl.h> 36 37 extern "C" static int PICL_get_cache_line_sizes_helper(picl_nodehdl_t nodeh, void *result); 38 39 40 class PICL { 41 // Get a value of the integer property. The value in the tree can be either 32 or 64 bit 42 // depending on the platform. The result is converted to int. 43 static int get_int_property(picl_nodehdl_t nodeh, const char* name, int* result) { 44 picl_propinfo_t pinfo; 45 picl_prophdl_t proph; 46 if (picl_get_prop_by_name(nodeh, name, &proph) != PICL_SUCCESS || 47 picl_get_propinfo(proph, &pinfo) != PICL_SUCCESS) { 48 return PICL_FAILURE; 49 } 50 51 if (pinfo.type != PICL_PTYPE_INT && pinfo.type != PICL_PTYPE_UNSIGNED_INT) { 52 assert(false, "Invalid property type"); 53 return PICL_FAILURE; 54 } 55 if (pinfo.size == sizeof(int64_t)) { 56 int64_t val; 57 if (picl_get_propval(proph, &val, sizeof(int64_t)) != PICL_SUCCESS) { 58 return PICL_FAILURE; 59 } 60 *result = static_cast<int>(val); 61 } else if (pinfo.size == sizeof(int32_t)) { 62 int32_t val; 63 if (picl_get_propval(proph, &val, sizeof(int32_t)) != PICL_SUCCESS) { 64 return PICL_FAILURE; 65 } 66 *result = static_cast<int>(val); 67 } else { 68 assert(false, "Unexpected integer property size"); 69 return PICL_FAILURE; 70 } 71 return PICL_SUCCESS; 72 } 73 74 75 static const int PROP_INCONSISTENT = -1; 76 static const int PROP_MISSING = -2; 77 // For every visited node make sure the specified property exists and has the same value 78 static int get_int_property_and_ensure_consistency(picl_nodehdl_t nodeh, const char* name, void *result) { 79 int *prev = static_cast<int*>(result); 80 int curr; 81 if (*prev >= 0) { // are still interested in walking? 82 if (get_int_property(nodeh, name, &curr) == PICL_SUCCESS) { 83 if (*prev == 0) { // first 84 *prev = curr; 85 return PICL_WALK_CONTINUE; 86 } else if (curr == *prev) { // others 87 return PICL_WALK_CONTINUE; 88 } else { 89 *prev = PROP_INCONSISTENT; 90 } 91 } else { 92 // missing property? 93 *prev = PROP_MISSING; 94 } 95 } 96 return PICL_WALK_TERMINATE; 97 } 98 99 struct CacheLineSizes { 100 int _L1_data; 101 int _L2; 102 CacheLineSizes() : _L1_data(0), _L2(0) {} 103 } _cache_line_sizes; 104 105 public: 106 static int get_cache_line_sizes(picl_nodehdl_t nodeh, void *result) 107 { 108 CacheLineSizes *sizes = static_cast<CacheLineSizes*>(result); 109 int r1 = get_int_property_and_ensure_consistency(nodeh, "l2-cache-line-size", &(sizes->_L2)); 110 int r2 = get_int_property_and_ensure_consistency(nodeh, "l1-dcache-line-size", &(sizes->_L1_data)); 111 if (r1 == PICL_WALK_TERMINATE && r2 == PICL_WALK_TERMINATE) { 112 return PICL_WALK_TERMINATE; 113 } 114 return PICL_WALK_CONTINUE; 115 } 116 117 PICL() { 118 if (picl_initialize() == PICL_SUCCESS) { 119 picl_nodehdl_t rooth; 120 if (picl_get_root(&rooth) == PICL_SUCCESS) { 121 // Visit all CPUs 122 CacheLineSizes cpu_cache_sizes, core_cache_sizes; 123 picl_walk_tree_by_class(rooth, "cpu", &cpu_cache_sizes, PICL_get_cache_line_sizes_helper); 124 picl_walk_tree_by_class(rooth, "core", &core_cache_sizes, PICL_get_cache_line_sizes_helper); 125 if (cpu_cache_sizes._L1_data != PROP_INCONSISTENT && core_cache_sizes._L1_data != PROP_INCONSISTENT) { 126 _cache_line_sizes._L1_data = MAX2(cpu_cache_sizes._L1_data, core_cache_sizes._L1_data); 127 } 128 if (cpu_cache_sizes._L2 != PROP_INCONSISTENT && core_cache_sizes._L2 != PROP_INCONSISTENT) { 129 _cache_line_sizes._L2 = MAX2(cpu_cache_sizes._L2, core_cache_sizes._L2); 130 } 131 } 132 picl_shutdown(); 133 } 134 } 135 136 unsigned int L1_data_cache_line_size() const { return _cache_line_sizes._L1_data; } 137 unsigned int L2_cache_line_size() const { return _cache_line_sizes._L2; } 138 }; 139 140 extern "C" static int PICL_get_cache_line_sizes_helper(picl_nodehdl_t nodeh, void *result) { 141 return PICL::get_cache_line_sizes(nodeh, result); 142 } 143 144 // We need to keep these here as long as we have to build on Solaris 145 // versions before 10. 146 #ifndef SI_ARCHITECTURE_32 147 #define SI_ARCHITECTURE_32 516 /* basic 32-bit SI_ARCHITECTURE */ 148 #endif 149 150 #ifndef SI_ARCHITECTURE_64 151 #define SI_ARCHITECTURE_64 517 /* basic 64-bit SI_ARCHITECTURE */ 152 #endif 153 154 static void do_sysinfo(int si, const char* string, int* features, int mask) { 155 char tmp; 156 size_t bufsize = sysinfo(si, &tmp, 1); 157 158 // All SI defines used below must be supported. 159 guarantee(bufsize != -1, "must be supported"); 160 161 char* buf = (char*) os::malloc(bufsize, mtInternal); 162 163 if (buf == NULL) 164 return; 165 166 if (sysinfo(si, buf, bufsize) == bufsize) { 167 // Compare the string. 168 if (strcmp(buf, string) == 0) { 169 *features |= mask; 170 } 171 } 172 173 os::free(buf); 174 } 175 176 int VM_Version::platform_features(int features) { 177 assert(os::Solaris::supports_getisax(), "getisax() must be available"); 178 179 // Check 32-bit architecture. 180 do_sysinfo(SI_ARCHITECTURE_32, "sparc", &features, v8_instructions_m); 181 182 // Check 64-bit architecture. 183 do_sysinfo(SI_ARCHITECTURE_64, "sparcv9", &features, generic_v9_m); 184 185 // Extract valid instruction set extensions. 186 uint_t avs[2]; 187 uint_t avn = os::Solaris::getisax(avs, 2); 188 assert(avn <= 2, "should return two or less av's"); 189 uint_t av = avs[0]; 190 191 #ifndef PRODUCT 192 if (PrintMiscellaneous && Verbose) { 193 tty->print("getisax(2) returned: " PTR32_FORMAT, av); 194 if (avn > 1) { 195 tty->print(", " PTR32_FORMAT, avs[1]); 196 } 197 tty->cr(); 198 } 199 #endif 200 201 if (av & AV_SPARC_MUL32) features |= hardware_mul32_m; 202 if (av & AV_SPARC_DIV32) features |= hardware_div32_m; 203 if (av & AV_SPARC_FSMULD) features |= hardware_fsmuld_m; 204 if (av & AV_SPARC_V8PLUS) features |= v9_instructions_m; 205 if (av & AV_SPARC_POPC) features |= hardware_popc_m; 206 if (av & AV_SPARC_VIS) features |= vis1_instructions_m; 207 if (av & AV_SPARC_VIS2) features |= vis2_instructions_m; 208 if (avn > 1) { 209 uint_t av2 = avs[1]; 210 #ifndef AV2_SPARC_SPARC5 211 #define AV2_SPARC_SPARC5 0x00000008 /* The 29 new fp and sub instructions */ 212 #endif 213 if (av2 & AV2_SPARC_SPARC5) features |= sparc5_instructions_m; 214 } 215 216 // We only build on Solaris 10 and up, but some of the values below 217 // are not defined on all versions of Solaris 10, so we define them, 218 // if necessary. 219 #ifndef AV_SPARC_ASI_BLK_INIT 220 #define AV_SPARC_ASI_BLK_INIT 0x0080 /* ASI_BLK_INIT_xxx ASI */ 221 #endif 222 if (av & AV_SPARC_ASI_BLK_INIT) features |= blk_init_instructions_m; 223 224 #ifndef AV_SPARC_FMAF 225 #define AV_SPARC_FMAF 0x0100 /* Fused Multiply-Add */ 226 #endif 227 if (av & AV_SPARC_FMAF) features |= fmaf_instructions_m; 228 229 #ifndef AV_SPARC_FMAU 230 #define AV_SPARC_FMAU 0x0200 /* Unfused Multiply-Add */ 231 #endif 232 if (av & AV_SPARC_FMAU) features |= fmau_instructions_m; 233 234 #ifndef AV_SPARC_VIS3 235 #define AV_SPARC_VIS3 0x0400 /* VIS3 instruction set extensions */ 236 #endif 237 if (av & AV_SPARC_VIS3) features |= vis3_instructions_m; 238 239 #ifndef AV_SPARC_CBCOND 240 #define AV_SPARC_CBCOND 0x10000000 /* compare and branch instrs supported */ 241 #endif 242 if (av & AV_SPARC_CBCOND) features |= cbcond_instructions_m; 243 244 #ifndef AV_SPARC_AES 245 #define AV_SPARC_AES 0x00020000 /* aes instrs supported */ 246 #endif 247 if (av & AV_SPARC_AES) features |= aes_instructions_m; 248 249 #ifndef AV_SPARC_SHA1 250 #define AV_SPARC_SHA1 0x00400000 /* sha1 instruction supported */ 251 #endif 252 if (av & AV_SPARC_SHA1) features |= sha1_instruction_m; 253 254 #ifndef AV_SPARC_SHA256 255 #define AV_SPARC_SHA256 0x00800000 /* sha256 instruction supported */ 256 #endif 257 if (av & AV_SPARC_SHA256) features |= sha256_instruction_m; 258 259 #ifndef AV_SPARC_SHA512 260 #define AV_SPARC_SHA512 0x01000000 /* sha512 instruction supported */ 261 #endif 262 if (av & AV_SPARC_SHA512) features |= sha512_instruction_m; 263 264 // Determine the machine type. 265 do_sysinfo(SI_MACHINE, "sun4v", &features, sun4v_m); 266 267 { 268 // Using kstat to determine the machine type. 269 kstat_ctl_t* kc = kstat_open(); 270 kstat_t* ksp = kstat_lookup(kc, (char*)"cpu_info", -1, NULL); 271 const char* implementation = "UNKNOWN"; 272 if (ksp != NULL) { 273 if (kstat_read(kc, ksp, NULL) != -1 && ksp->ks_data != NULL) { 274 kstat_named_t* knm = (kstat_named_t *)ksp->ks_data; 275 for (int i = 0; i < ksp->ks_ndata; i++) { 276 if (strcmp((const char*)&(knm[i].name),"implementation") == 0) { 277 implementation = KSTAT_NAMED_STR_PTR(&knm[i]); 278 #ifndef PRODUCT 279 if (PrintMiscellaneous && Verbose) { 280 tty->print_cr("cpu_info.implementation: %s", implementation); 281 } 282 #endif 283 // Convert to UPPER case before compare. 284 char* impl = os::strdup_check_oom(implementation); 285 286 for (int i = 0; impl[i] != 0; i++) 287 impl[i] = (char)toupper((uint)impl[i]); 288 289 if (strstr(impl, "SPARC64") != NULL) { 290 features |= sparc64_family_m; 291 } else if (strstr(impl, "SPARC-M") != NULL) { 292 // M-series SPARC is based on T-series. 293 features |= (M_family_m | T_family_m); 294 } else if (strstr(impl, "SPARC-T") != NULL) { 295 features |= T_family_m; 296 if (strstr(impl, "SPARC-T1") != NULL) { 297 features |= T1_model_m; 298 } 299 } else { 300 if (strstr(impl, "SPARC") == NULL) { 301 #ifndef PRODUCT 302 // kstat on Solaris 8 virtual machines (branded zones) 303 // returns "(unsupported)" implementation. Solaris 8 is not 304 // supported anymore, but include this check to be on the 305 // safe side. 306 warning("kstat cpu_info implementation = '%s', assume generic SPARC", impl); 307 #endif 308 implementation = "SPARC"; 309 } 310 } 311 os::free((void*)impl); 312 break; 313 } 314 } // for( 315 } 316 } 317 assert(strcmp(implementation, "UNKNOWN") != 0, 318 "unknown cpu info (changed kstat interface?)"); 319 kstat_close(kc); 320 } 321 322 // Figure out cache line sizes using PICL 323 PICL picl; 324 _L1_data_cache_line_size = picl.L1_data_cache_line_size(); 325 _L2_cache_line_size = picl.L2_cache_line_size(); 326 327 return features; 328 }