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