Thu, 05 Sep 2019 13:07:31 +0800
#9372 Refactor VM_Version, removed UseLoongsonISA and Use3A3000, added UseLEXT1, UseLEXT2, UseLEXT3.
Summary: used cpucfg to detect cpu features
Reviewed-by: wanghaomin
1 /*
2 * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
3 * Copyright (c) 2015, 2019, Loongson Technology. All rights reserved.
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 *
6 * This code is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 only, as
8 * published by the Free Software Foundation.
9 *
10 * This code is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * questions.
23 *
24 */
26 #include "precompiled.hpp"
27 #include "asm/macroAssembler.hpp"
28 #include "asm/macroAssembler.inline.hpp"
29 #include "memory/resourceArea.hpp"
30 #include "runtime/java.hpp"
31 #include "runtime/stubCodeGenerator.hpp"
32 #include "vm_version_mips.hpp"
33 #ifdef TARGET_OS_FAMILY_linux
34 # include "os_linux.inline.hpp"
35 #endif
37 int VM_Version::_cpuFeatures;
38 const char* VM_Version::_features_str = "";
39 VM_Version::CpuidInfo VM_Version::_cpuid_info = { 0, };
40 volatile bool VM_Version::_is_determine_cpucfg_supported_running = false;
41 bool VM_Version::_is_cpucfg_instruction_supported = true;
42 bool VM_Version::_cpu_info_is_initialized = false;
44 static BufferBlob* stub_blob;
45 static const int stub_size = 600;
47 extern "C" {
48 typedef void (*get_cpu_info_stub_t)(void*);
49 }
50 static get_cpu_info_stub_t get_cpu_info_stub = NULL;
53 class VM_Version_StubGenerator: public StubCodeGenerator {
54 public:
56 VM_Version_StubGenerator(CodeBuffer *c) : StubCodeGenerator(c) {}
58 address generate_get_cpu_info() {
59 assert(!VM_Version::cpu_info_is_initialized(), "VM_Version should not be initialized");
60 StubCodeMark mark(this, "VM_Version", "get_cpu_info_stub");
61 # define __ _masm->
63 address start = __ pc();
65 __ enter();
66 __ push(AT);
67 __ push(V0);
69 __ li(AT, (long)0);
70 __ cpucfg(V0, AT);
71 __ lw(AT, A0, in_bytes(VM_Version::Loongson_Cpucfg_id0_offset()));
72 __ sw(V0, A0, in_bytes(VM_Version::Loongson_Cpucfg_id0_offset()));
74 __ li(AT, 1);
75 __ cpucfg(V0, AT);
76 __ lw(AT, A0, in_bytes(VM_Version::Loongson_Cpucfg_id1_offset()));
77 __ sw(V0, A0, in_bytes(VM_Version::Loongson_Cpucfg_id1_offset()));
79 __ li(AT, 2);
80 __ cpucfg(V0, AT);
81 __ lw(AT, A0, in_bytes(VM_Version::Loongson_Cpucfg_id2_offset()));
82 __ sw(V0, A0, in_bytes(VM_Version::Loongson_Cpucfg_id2_offset()));
84 __ pop(V0);
85 __ pop(AT);
86 __ leave();
87 __ jr(RA);
88 __ delayed()->nop();
89 # undef __
91 return start;
92 };
93 };
95 uint32_t VM_Version::get_feature_flags_by_cpucfg() {
96 uint32_t result = 0;
97 if (_cpuid_info.cpucfg_info_id1.bits.MMI != 0)
98 result |= CPU_MMI;
99 if (_cpuid_info.cpucfg_info_id1.bits.MSA1 != 0)
100 result |= CPU_MSA1_0;
101 if (_cpuid_info.cpucfg_info_id1.bits.MSA2 != 0)
102 result |= CPU_MSA2_0;
103 if (_cpuid_info.cpucfg_info_id1.bits.CGP != 0)
104 result |= CPU_CGP;
105 if (_cpuid_info.cpucfg_info_id1.bits.LSX1 != 0)
106 result |= CPU_LSX1;
107 if (_cpuid_info.cpucfg_info_id1.bits.LSX2 != 0)
108 result |= CPU_LSX2;
109 if (_cpuid_info.cpucfg_info_id1.bits.LASX != 0)
110 result |= CPU_LASX;
111 if (_cpuid_info.cpucfg_info_id1.bits.LLSYNC != 0)
112 result |= CPU_LLSYNC;
113 if (_cpuid_info.cpucfg_info_id1.bits.TGTSYNC != 0)
114 result |= CPU_TGTSYNC;
115 if (_cpuid_info.cpucfg_info_id1.bits.MUALP != 0)
116 result |= CPU_MUALP;
117 if (_cpuid_info.cpucfg_info_id2.bits.LEXT1 != 0)
118 result |= CPU_LEXT1;
119 if (_cpuid_info.cpucfg_info_id2.bits.LEXT2 != 0)
120 result |= CPU_LEXT2;
121 if (_cpuid_info.cpucfg_info_id2.bits.LEXT3 != 0)
122 result |= CPU_LEXT3;
123 if (_cpuid_info.cpucfg_info_id2.bits.LAMO != 0)
124 result |= CPU_LAMO;
125 if (_cpuid_info.cpucfg_info_id2.bits.LPIXU != 0)
126 result |= CPU_LPIXU;
128 result |= CPU_ULSYNC;
130 return result;
131 }
133 void read_cpu_info(const char *path, char *result) {
134 FILE *ptr;
135 char buf[1024];
136 int i = 0;
137 if((ptr=fopen(path, "r")) != NULL) {
138 while(fgets(buf, 1024, ptr)!=NULL) {
139 strcat(result,buf);
140 i++;
141 if (i == 10) break;
142 }
143 fclose(ptr);
144 } else {
145 warning("Can't detect CPU info - cannot open %s", path);
146 }
147 }
149 void strlwr(char *str) {
150 for (; *str!='\0'; str++)
151 *str = tolower(*str);
152 }
154 int VM_Version::get_feature_flags_by_cpuinfo(int features) {
155 assert(!cpu_info_is_initialized(), "VM_Version should not be initialized");
157 char res[10240];
158 int i;
159 memset(res, '\0', 10240 * sizeof(char));
160 read_cpu_info("/proc/cpuinfo", res);
161 // res is converted to lower case
162 strlwr(res);
164 if (strstr(res, "loongson")) {
165 // Loongson CPU
166 features |= CPU_LOONGSON;
168 const struct Loongson_Cpuinfo loongson_cpuinfo[] = {
169 {L_3A1000, "3a1000"},
170 {L_3B1500, "3b1500"},
171 {L_3A2000, "3a2000"},
172 {L_3B2000, "3b2000"},
173 {L_3A3000, "3a3000"},
174 {L_3B3000, "3b3000"},
175 {L_2K1000, "2k1000"},
176 {L_UNKNOWN, "unknown"}
177 };
179 // Loongson Family
180 int detected = 0;
181 for (i = 0; i <= L_UNKNOWN; i++) {
182 switch (i) {
183 // 3A1000 and 3B1500 may use an old kernel and further comparsion is needed
184 // test PRID REV in /proc/cpuinfo
185 // 3A1000: V0.5, model name: ICT Loongson-3A V0.5 FPU V0.1
186 // 3B1500: V0.7, model name: ICT Loongson-3B V0.7 FPU V0.1
187 case L_3A1000:
188 if (strstr(res, loongson_cpuinfo[i].match_str) || strstr(res, "loongson-3a v0.5")) {
189 features |= CPU_LOONGSON_GS464;
190 detected++;
191 //tty->print_cr("3A1000 platform");
192 }
193 break;
194 case L_3B1500:
195 if (strstr(res, loongson_cpuinfo[i].match_str) || strstr(res, "loongson-3b v0.7")) {
196 features |= CPU_LOONGSON_GS464;
197 detected++;
198 //tty->print_cr("3B1500 platform");
199 }
200 break;
201 case L_3A2000:
202 case L_3B2000:
203 case L_3A3000:
204 case L_3B3000:
205 if (strstr(res, loongson_cpuinfo[i].match_str)) {
206 features |= CPU_LOONGSON_GS464E;
207 detected++;
208 //tty->print_cr("3A2000/3A3000/3B2000/3B3000 platform");
209 }
210 break;
211 case L_2K1000:
212 if (strstr(res, loongson_cpuinfo[i].match_str)) {
213 features |= CPU_LOONGSON_GS264;
214 detected++;
215 //tty->print_cr("2K1000 platform");
216 }
217 break;
218 case L_UNKNOWN:
219 if (detected == 0) {
220 detected++;
221 //tty->print_cr("unknown Loongson platform");
222 }
223 break;
224 default:
225 ShouldNotReachHere();
226 }
227 }
228 assert (detected == 1, "one and only one of LOONGSON_CPU_FAMILY should be detected");
229 } else { // not Loongson
230 // Not Loongson CPU
231 //tty->print_cr("MIPS platform");
232 }
234 if (features & CPU_LOONGSON_GS264) {
235 features |= CPU_LEXT1;
236 features |= CPU_LEXT2;
237 features |= CPU_TGTSYNC;
238 features |= CPU_ULSYNC;
239 features |= CPU_MSA1_0;
240 features |= CPU_LSX1;
241 } else if (features & CPU_LOONGSON_GS464) {
242 features |= CPU_LEXT1;
243 features |= CPU_LLSYNC;
244 features |= CPU_TGTSYNC;
245 } else if (features & CPU_LOONGSON_GS464E) {
246 features |= CPU_LEXT1;
247 features |= CPU_LEXT2;
248 features |= CPU_LEXT3;
249 features |= CPU_TGTSYNC;
250 features |= CPU_ULSYNC;
251 } else if (features & CPU_LOONGSON) {
252 // unknow loongson
253 features |= CPU_LLSYNC;
254 features |= CPU_TGTSYNC;
255 features |= CPU_ULSYNC;
256 }
257 VM_Version::_cpu_info_is_initialized = true;
259 return features;
260 }
262 void VM_Version::get_processor_features() {
264 clean_cpuFeatures();
266 // test if cpucfg instruction is supported
267 VM_Version::_is_determine_cpucfg_supported_running = true;
268 __asm__ __volatile__(
269 ".insn \n\t"
270 ".word (0xc8080118)\n\t" // cpucfg zero, zero
271 :
272 :
273 :
274 );
275 VM_Version::_is_determine_cpucfg_supported_running = false;
277 if (supports_cpucfg()) {
278 get_cpu_info_stub(&_cpuid_info);
279 _cpuFeatures = get_feature_flags_by_cpucfg();
280 // Only Loongson CPUs support cpucfg
281 _cpuFeatures |= CPU_LOONGSON;
282 } else {
283 _cpuFeatures = get_feature_flags_by_cpuinfo(0);
284 }
286 _supports_cx8 = true;
288 if (UseG1GC && FLAG_IS_DEFAULT(MaxGCPauseMillis)) {
289 FLAG_SET_CMDLINE(uintx, MaxGCPauseMillis, 650);
290 }
292 #ifdef COMPILER2
293 if (MaxVectorSize > 0) {
294 if (!is_power_of_2(MaxVectorSize)) {
295 warning("MaxVectorSize must be a power of 2");
296 MaxVectorSize = 8;
297 }
298 if (MaxVectorSize > 0 && supports_ps()) {
299 MaxVectorSize = 8;
300 } else {
301 MaxVectorSize = 0;
302 }
303 }
304 //
305 // Vector optimization of MIPS works in most cases, but cannot pass hotspot/test/compiler/6340864/TestFloatVect.java.
306 // Vector optimization was closed by default.
307 // The reasons:
308 // 1. The kernel does not have emulation of PS instructions yet, so the emulation of PS instructions must be done in JVM, see JVM_handle_linux_signal.
309 // 2. It seems the gcc4.4.7 had some bug related to ucontext_t, which is used in signal handler to emulate PS instructions.
310 //
311 if (FLAG_IS_DEFAULT(MaxVectorSize)) {
312 MaxVectorSize = 0;
313 }
315 #endif
317 if (needs_llsync() && needs_tgtsync() && !needs_ulsync()) {
318 if (FLAG_IS_DEFAULT(UseSyncLevel)) {
319 FLAG_SET_DEFAULT(UseSyncLevel, 1000);
320 }
321 } else if (!needs_llsync() && needs_tgtsync() && needs_ulsync()) {
322 if (FLAG_IS_DEFAULT(UseSyncLevel)) {
323 FLAG_SET_DEFAULT(UseSyncLevel, 2000);
324 }
325 } else if (needs_llsync() && needs_llsync() && needs_ulsync()) {
326 if (FLAG_IS_DEFAULT(UseSyncLevel)) {
327 FLAG_SET_DEFAULT(UseSyncLevel, 3000);
328 }
329 } else if (!needs_llsync() && !needs_llsync() && !needs_ulsync()) {
330 if (FLAG_IS_DEFAULT(UseSyncLevel)) {
331 FLAG_SET_DEFAULT(UseSyncLevel, 0);
332 }
333 } else {
334 assert(false, "Should Not Reach Here, what is the cpu type?");
335 }
337 if (supports_lext1()) {
338 if (FLAG_IS_DEFAULT(UseLEXT1)) {
339 FLAG_SET_DEFAULT(UseLEXT1, true);
340 }
341 } else if (UseLEXT1) {
342 warning("LEXT1 instructions are not available on this CPU");
343 FLAG_SET_DEFAULT(UseLEXT1, false);
344 }
346 if (supports_lext2()) {
347 if (FLAG_IS_DEFAULT(UseLEXT2)) {
348 FLAG_SET_DEFAULT(UseLEXT2, true);
349 }
350 } else if (UseLEXT2) {
351 warning("LEXT2 instructions are not available on this CPU");
352 FLAG_SET_DEFAULT(UseLEXT2, false);
353 }
355 if (supports_lext3()) {
356 if (FLAG_IS_DEFAULT(UseLEXT3)) {
357 FLAG_SET_DEFAULT(UseLEXT3, true);
358 }
359 } else if (UseLEXT3) {
360 warning("LEXT3 instructions are not available on this CPU");
361 FLAG_SET_DEFAULT(UseLEXT3, false);
362 }
364 if (UseLEXT2) {
365 if (FLAG_IS_DEFAULT(UseCountTrailingZerosInstructionMIPS64)) {
366 FLAG_SET_DEFAULT(UseCountTrailingZerosInstructionMIPS64, 1);
367 }
368 } else if (UseCountTrailingZerosInstructionMIPS64) {
369 if (!FLAG_IS_DEFAULT(UseCountTrailingZerosInstructionMIPS64))
370 warning("ctz/dctz instructions are not available on this CPU");
371 FLAG_SET_DEFAULT(UseCountTrailingZerosInstructionMIPS64, 0);
372 }
374 if (TieredCompilation) {
375 if (!FLAG_IS_DEFAULT(TieredCompilation))
376 warning("TieredCompilation not supported");
377 FLAG_SET_DEFAULT(TieredCompilation, false);
378 }
380 char buf[256];
381 bool is_unknown_loongson_cpu = is_loongson() && !is_gs464() && !is_gs464e() && !is_gs264() && !supports_cpucfg();
383 jio_snprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s, UseSyncLevel:%d",
384 (is_loongson() ? "MIPS-compatible Loongson CPU" : "MIPS CPU"),
385 (is_gs464() ? ", GS464 (3A1000/3B1500)" : ""),
386 (is_gs464e() ? ", GS464E (3A2000/3A3000/3B2000/3B3000)" : ""),
387 (is_gs264() ? ", GS264 (2K1000)" : ""),
388 (is_unknown_loongson_cpu ? ", Unknown Loongson CPU" : ""),
389 (supports_dsp() ? ", dsp" : ""),
390 (supports_ps() ? ", ps" : ""),
391 (supports_3d() ? ", 3d" : ""),
392 (supports_mmi() ? ", mmi" : ""),
393 (supports_msa1_0() ? ", msa1_0" : ""),
394 (supports_msa2_0() ? ", msa2_0" : ""),
395 (supports_lsx1() ? ", lsx1" : ""),
396 (supports_lsx2() ? ", lsx2" : ""),
397 (supports_lasx() ? ", lasx" : ""),
398 (supports_lext1() ? ", lext1" : ""),
399 (supports_lext2() ? ", lext2" : ""),
400 (supports_lext3() ? ", lext3" : ""),
401 (supports_cgp() ? ", aes, crc, sha1, sha256, sha512" : ""),
402 (supports_lamo() ? ", lamo" : ""),
403 (supports_lpixu() ? ", lpixu" : ""),
404 (needs_llsync() ? ", llsync" : ""),
405 (needs_tgtsync() ? ", tgtsync": ""),
406 (needs_ulsync() ? ", ulsync": ""),
407 (supports_mualp() ? ", mualp" : ""),
408 UseSyncLevel);
409 _features_str = strdup(buf);
411 if (FLAG_IS_DEFAULT(AllocatePrefetchStyle)) {
412 FLAG_SET_DEFAULT(AllocatePrefetchStyle, 1);
413 }
415 if (FLAG_IS_DEFAULT(AllocatePrefetchLines)) {
416 FLAG_SET_DEFAULT(AllocatePrefetchLines, 1);
417 }
419 if (FLAG_IS_DEFAULT(AllocatePrefetchStepSize)) {
420 FLAG_SET_DEFAULT(AllocatePrefetchStepSize, 64);
421 }
423 if (FLAG_IS_DEFAULT(AllocatePrefetchDistance)) {
424 FLAG_SET_DEFAULT(AllocatePrefetchDistance, 64);
425 }
427 if (FLAG_IS_DEFAULT(AllocateInstancePrefetchLines)) {
428 FLAG_SET_DEFAULT(AllocateInstancePrefetchLines, 1);
429 }
431 if (UseSHA) {
432 warning("SHA instructions are not available on this CPU");
433 FLAG_SET_DEFAULT(UseSHA, false);
434 }
436 if (UseSHA1Intrinsics || UseSHA256Intrinsics || UseSHA512Intrinsics) {
437 warning("SHA intrinsics are not available on this CPU");
438 FLAG_SET_DEFAULT(UseSHA1Intrinsics, false);
439 FLAG_SET_DEFAULT(UseSHA256Intrinsics, false);
440 FLAG_SET_DEFAULT(UseSHA512Intrinsics, false);
441 }
443 if (UseAES) {
444 if (!FLAG_IS_DEFAULT(UseAES)) {
445 warning("AES instructions are not available on this CPU");
446 FLAG_SET_DEFAULT(UseAES, false);
447 }
448 }
450 if (UseCRC32Intrinsics) {
451 if (!FLAG_IS_DEFAULT(UseCRC32Intrinsics)) {
452 warning("CRC32Intrinsics instructions are not available on this CPU");
453 FLAG_SET_DEFAULT(UseCRC32Intrinsics, false);
454 }
455 }
457 if (UseAESIntrinsics) {
458 if (!FLAG_IS_DEFAULT(UseAESIntrinsics)) {
459 warning("AES intrinsics are not available on this CPU");
460 FLAG_SET_DEFAULT(UseAESIntrinsics, false);
461 }
462 }
464 if (FLAG_IS_DEFAULT(UseMontgomeryMultiplyIntrinsic)) {
465 UseMontgomeryMultiplyIntrinsic = true;
466 }
467 if (FLAG_IS_DEFAULT(UseMontgomerySquareIntrinsic)) {
468 UseMontgomerySquareIntrinsic = true;
469 }
471 }
473 void VM_Version::initialize() {
474 ResourceMark rm;
475 // Making this stub must be FIRST use of assembler
477 stub_blob = BufferBlob::create("get_cpu_info_stub", stub_size);
478 if (stub_blob == NULL) {
479 vm_exit_during_initialization("Unable to allocate get_cpu_info_stub");
480 }
481 CodeBuffer c(stub_blob);
482 VM_Version_StubGenerator g(&c);
483 get_cpu_info_stub = CAST_TO_FN_PTR(get_cpu_info_stub_t,
484 g.generate_get_cpu_info());
486 get_processor_features();
487 }