1/*
2 * Copyright (c) 2013, 2019, 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 "jvm.h"
27#include "utilities/macros.hpp"
28#include "asm/macroAssembler.hpp"
29#include "asm/macroAssembler.inline.hpp"
30#include "memory/allocation.inline.hpp"
31#include "memory/resourceArea.hpp"
32#include "runtime/java.hpp"
33#include "runtime/stubCodeGenerator.hpp"
34#include "vm_version_ext_x86.hpp"
35
36typedef enum {
37 CPU_FAMILY_8086_8088 = 0,
38 CPU_FAMILY_INTEL_286 = 2,
39 CPU_FAMILY_INTEL_386 = 3,
40 CPU_FAMILY_INTEL_486 = 4,
41 CPU_FAMILY_PENTIUM = 5,
42 CPU_FAMILY_PENTIUMPRO = 6, // Same family several models
43 CPU_FAMILY_PENTIUM_4 = 0xF
44} FamilyFlag;
45
46typedef enum {
47 RDTSCP_FLAG = 0x08000000, // bit 27
48 INTEL64_FLAG = 0x20000000 // bit 29
49} _featureExtendedEdxFlag;
50
51#define CPUID_STANDARD_FN 0x0
52#define CPUID_STANDARD_FN_1 0x1
53#define CPUID_STANDARD_FN_4 0x4
54#define CPUID_STANDARD_FN_B 0xb
55
56#define CPUID_EXTENDED_FN 0x80000000
57#define CPUID_EXTENDED_FN_1 0x80000001
58#define CPUID_EXTENDED_FN_2 0x80000002
59#define CPUID_EXTENDED_FN_3 0x80000003
60#define CPUID_EXTENDED_FN_4 0x80000004
61#define CPUID_EXTENDED_FN_7 0x80000007
62#define CPUID_EXTENDED_FN_8 0x80000008
63
64typedef enum {
65 FPU_FLAG = 0x00000001,
66 VME_FLAG = 0x00000002,
67 DE_FLAG = 0x00000004,
68 PSE_FLAG = 0x00000008,
69 TSC_FLAG = 0x00000010,
70 MSR_FLAG = 0x00000020,
71 PAE_FLAG = 0x00000040,
72 MCE_FLAG = 0x00000080,
73 CX8_FLAG = 0x00000100,
74 APIC_FLAG = 0x00000200,
75 SEP_FLAG = 0x00000800,
76 MTRR_FLAG = 0x00001000,
77 PGE_FLAG = 0x00002000,
78 MCA_FLAG = 0x00004000,
79 CMOV_FLAG = 0x00008000,
80 PAT_FLAG = 0x00010000,
81 PSE36_FLAG = 0x00020000,
82 PSNUM_FLAG = 0x00040000,
83 CLFLUSH_FLAG = 0x00080000,
84 DTS_FLAG = 0x00200000,
85 ACPI_FLAG = 0x00400000,
86 MMX_FLAG = 0x00800000,
87 FXSR_FLAG = 0x01000000,
88 SSE_FLAG = 0x02000000,
89 SSE2_FLAG = 0x04000000,
90 SS_FLAG = 0x08000000,
91 HTT_FLAG = 0x10000000,
92 TM_FLAG = 0x20000000
93} FeatureEdxFlag;
94
95static BufferBlob* cpuid_brand_string_stub_blob;
96static const int cpuid_brand_string_stub_size = 550;
97
98extern "C" {
99 typedef void (*getCPUIDBrandString_stub_t)(void*);
100}
101
102static getCPUIDBrandString_stub_t getCPUIDBrandString_stub = NULL;
103
104class VM_Version_Ext_StubGenerator: public StubCodeGenerator {
105 public:
106
107 VM_Version_Ext_StubGenerator(CodeBuffer *c) : StubCodeGenerator(c) {}
108
109 address generate_getCPUIDBrandString(void) {
110 // Flags to test CPU type.
111 const uint32_t HS_EFL_AC = 0x40000;
112 const uint32_t HS_EFL_ID = 0x200000;
113 // Values for when we don't have a CPUID instruction.
114 const int CPU_FAMILY_SHIFT = 8;
115 const uint32_t CPU_FAMILY_386 = (3 << CPU_FAMILY_SHIFT);
116 const uint32_t CPU_FAMILY_486 = (4 << CPU_FAMILY_SHIFT);
117
118 Label detect_486, cpu486, detect_586, done, ext_cpuid;
119
120 StubCodeMark mark(this, "VM_Version_Ext", "getCPUIDNameInfo_stub");
121# define __ _masm->
122
123 address start = __ pc();
124
125 //
126 // void getCPUIDBrandString(VM_Version::CpuidInfo* cpuid_info);
127 //
128 // LP64: rcx and rdx are first and second argument registers on windows
129
130 __ push(rbp);
131#ifdef _LP64
132 __ mov(rbp, c_rarg0); // cpuid_info address
133#else
134 __ movptr(rbp, Address(rsp, 8)); // cpuid_info address
135#endif
136 __ push(rbx);
137 __ push(rsi);
138 __ pushf(); // preserve rbx, and flags
139 __ pop(rax);
140 __ push(rax);
141 __ mov(rcx, rax);
142 //
143 // if we are unable to change the AC flag, we have a 386
144 //
145 __ xorl(rax, HS_EFL_AC);
146 __ push(rax);
147 __ popf();
148 __ pushf();
149 __ pop(rax);
150 __ cmpptr(rax, rcx);
151 __ jccb(Assembler::notEqual, detect_486);
152
153 __ movl(rax, CPU_FAMILY_386);
154 __ jmp(done);
155
156 //
157 // If we are unable to change the ID flag, we have a 486 which does
158 // not support the "cpuid" instruction.
159 //
160 __ bind(detect_486);
161 __ mov(rax, rcx);
162 __ xorl(rax, HS_EFL_ID);
163 __ push(rax);
164 __ popf();
165 __ pushf();
166 __ pop(rax);
167 __ cmpptr(rcx, rax);
168 __ jccb(Assembler::notEqual, detect_586);
169
170 __ bind(cpu486);
171 __ movl(rax, CPU_FAMILY_486);
172 __ jmp(done);
173
174 //
175 // At this point, we have a chip which supports the "cpuid" instruction
176 //
177 __ bind(detect_586);
178 __ xorl(rax, rax);
179 __ cpuid();
180 __ orl(rax, rax);
181 __ jcc(Assembler::equal, cpu486); // if cpuid doesn't support an input
182 // value of at least 1, we give up and
183 // assume a 486
184
185 //
186 // Extended cpuid(0x80000000) for processor brand string detection
187 //
188 __ bind(ext_cpuid);
189 __ movl(rax, CPUID_EXTENDED_FN);
190 __ cpuid();
191 __ cmpl(rax, CPUID_EXTENDED_FN_4);
192 __ jcc(Assembler::below, done);
193
194 //
195 // Extended cpuid(0x80000002) // first 16 bytes in brand string
196 //
197 __ movl(rax, CPUID_EXTENDED_FN_2);
198 __ cpuid();
199 __ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_0_offset())));
200 __ movl(Address(rsi, 0), rax);
201 __ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_1_offset())));
202 __ movl(Address(rsi, 0), rbx);
203 __ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_2_offset())));
204 __ movl(Address(rsi, 0), rcx);
205 __ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_3_offset())));
206 __ movl(Address(rsi,0), rdx);
207
208 //
209 // Extended cpuid(0x80000003) // next 16 bytes in brand string
210 //
211 __ movl(rax, CPUID_EXTENDED_FN_3);
212 __ cpuid();
213 __ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_4_offset())));
214 __ movl(Address(rsi, 0), rax);
215 __ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_5_offset())));
216 __ movl(Address(rsi, 0), rbx);
217 __ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_6_offset())));
218 __ movl(Address(rsi, 0), rcx);
219 __ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_7_offset())));
220 __ movl(Address(rsi,0), rdx);
221
222 //
223 // Extended cpuid(0x80000004) // last 16 bytes in brand string
224 //
225 __ movl(rax, CPUID_EXTENDED_FN_4);
226 __ cpuid();
227 __ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_8_offset())));
228 __ movl(Address(rsi, 0), rax);
229 __ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_9_offset())));
230 __ movl(Address(rsi, 0), rbx);
231 __ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_10_offset())));
232 __ movl(Address(rsi, 0), rcx);
233 __ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_11_offset())));
234 __ movl(Address(rsi,0), rdx);
235
236 //
237 // return
238 //
239 __ bind(done);
240 __ popf();
241 __ pop(rsi);
242 __ pop(rbx);
243 __ pop(rbp);
244 __ ret(0);
245
246# undef __
247
248 return start;
249 };
250};
251
252
253// VM_Version_Ext statics
254const size_t VM_Version_Ext::VENDOR_LENGTH = 13;
255const size_t VM_Version_Ext::CPU_EBS_MAX_LENGTH = (3 * 4 * 4 + 1);
256const size_t VM_Version_Ext::CPU_TYPE_DESC_BUF_SIZE = 256;
257const size_t VM_Version_Ext::CPU_DETAILED_DESC_BUF_SIZE = 4096;
258char* VM_Version_Ext::_cpu_brand_string = NULL;
259jlong VM_Version_Ext::_max_qualified_cpu_frequency = 0;
260
261int VM_Version_Ext::_no_of_threads = 0;
262int VM_Version_Ext::_no_of_cores = 0;
263int VM_Version_Ext::_no_of_packages = 0;
264
265void VM_Version_Ext::initialize(void) {
266 ResourceMark rm;
267
268 cpuid_brand_string_stub_blob = BufferBlob::create("getCPUIDBrandString_stub", cpuid_brand_string_stub_size);
269 if (cpuid_brand_string_stub_blob == NULL) {
270 vm_exit_during_initialization("Unable to allocate getCPUIDBrandString_stub");
271 }
272 CodeBuffer c(cpuid_brand_string_stub_blob);
273 VM_Version_Ext_StubGenerator g(&c);
274 getCPUIDBrandString_stub = CAST_TO_FN_PTR(getCPUIDBrandString_stub_t,
275 g.generate_getCPUIDBrandString());
276}
277
278const char* VM_Version_Ext::cpu_model_description(void) {
279 uint32_t cpu_family = extended_cpu_family();
280 uint32_t cpu_model = extended_cpu_model();
281 const char* model = NULL;
282
283 if (cpu_family == CPU_FAMILY_PENTIUMPRO) {
284 for (uint32_t i = 0; i <= cpu_model; i++) {
285 model = _model_id_pentium_pro[i];
286 if (model == NULL) {
287 break;
288 }
289 }
290 }
291 return model;
292}
293
294const char* VM_Version_Ext::cpu_brand_string(void) {
295 if (_cpu_brand_string == NULL) {
296 _cpu_brand_string = NEW_C_HEAP_ARRAY_RETURN_NULL(char, CPU_EBS_MAX_LENGTH, mtInternal);
297 if (NULL == _cpu_brand_string) {
298 return NULL;
299 }
300 int ret_val = cpu_extended_brand_string(_cpu_brand_string, CPU_EBS_MAX_LENGTH);
301 if (ret_val != OS_OK) {
302 FREE_C_HEAP_ARRAY(char, _cpu_brand_string);
303 _cpu_brand_string = NULL;
304 }
305 }
306 return _cpu_brand_string;
307}
308
309const char* VM_Version_Ext::cpu_brand(void) {
310 const char* brand = NULL;
311
312 if ((_cpuid_info.std_cpuid1_ebx.value & 0xFF) > 0) {
313 int brand_num = _cpuid_info.std_cpuid1_ebx.value & 0xFF;
314 brand = _brand_id[0];
315 for (int i = 0; brand != NULL && i <= brand_num; i += 1) {
316 brand = _brand_id[i];
317 }
318 }
319 return brand;
320}
321
322bool VM_Version_Ext::cpu_is_em64t(void) {
323 return ((_cpuid_info.ext_cpuid1_edx.value & INTEL64_FLAG) == INTEL64_FLAG);
324}
325
326bool VM_Version_Ext::is_netburst(void) {
327 return (is_intel() && (extended_cpu_family() == CPU_FAMILY_PENTIUM_4));
328}
329
330bool VM_Version_Ext::supports_tscinv_ext(void) {
331 if (!supports_tscinv_bit()) {
332 return false;
333 }
334
335 if (is_intel()) {
336 return true;
337 }
338
339 if (is_amd()) {
340 return !is_amd_Barcelona();
341 }
342
343 if (is_hygon()) {
344 return true;
345 }
346
347 return false;
348}
349
350void VM_Version_Ext::resolve_cpu_information_details(void) {
351
352 // in future we want to base this information on proper cpu
353 // and cache topology enumeration such as:
354 // Intel 64 Architecture Processor Topology Enumeration
355 // which supports system cpu and cache topology enumeration
356 // either using 2xAPICIDs or initial APICIDs
357
358 // currently only rough cpu information estimates
359 // which will not necessarily reflect the exact configuration of the system
360
361 // this is the number of logical hardware threads
362 // visible to the operating system
363 _no_of_threads = os::processor_count();
364
365 // find out number of threads per cpu package
366 int threads_per_package = threads_per_core() * cores_per_cpu();
367
368 // use amount of threads visible to the process in order to guess number of sockets
369 _no_of_packages = _no_of_threads / threads_per_package;
370
371 // process might only see a subset of the total number of threads
372 // from a single processor package. Virtualization/resource management for example.
373 // If so then just write a hard 1 as num of pkgs.
374 if (0 == _no_of_packages) {
375 _no_of_packages = 1;
376 }
377
378 // estimate the number of cores
379 _no_of_cores = cores_per_cpu() * _no_of_packages;
380}
381
382int VM_Version_Ext::number_of_threads(void) {
383 if (_no_of_threads == 0) {
384 resolve_cpu_information_details();
385 }
386 return _no_of_threads;
387}
388
389int VM_Version_Ext::number_of_cores(void) {
390 if (_no_of_cores == 0) {
391 resolve_cpu_information_details();
392 }
393 return _no_of_cores;
394}
395
396int VM_Version_Ext::number_of_sockets(void) {
397 if (_no_of_packages == 0) {
398 resolve_cpu_information_details();
399 }
400 return _no_of_packages;
401}
402
403const char* VM_Version_Ext::cpu_family_description(void) {
404 int cpu_family_id = extended_cpu_family();
405 if (is_amd()) {
406 if (cpu_family_id < ExtendedFamilyIdLength_AMD) {
407 return _family_id_amd[cpu_family_id];
408 }
409 }
410 if (is_intel()) {
411 if (cpu_family_id == CPU_FAMILY_PENTIUMPRO) {
412 return cpu_model_description();
413 }
414 if (cpu_family_id < ExtendedFamilyIdLength_INTEL) {
415 return _family_id_intel[cpu_family_id];
416 }
417 }
418 if (is_hygon()) {
419 return "Dhyana";
420 }
421 return "Unknown x86";
422}
423
424int VM_Version_Ext::cpu_type_description(char* const buf, size_t buf_len) {
425 assert(buf != NULL, "buffer is NULL!");
426 assert(buf_len >= CPU_TYPE_DESC_BUF_SIZE, "buffer len should at least be == CPU_TYPE_DESC_BUF_SIZE!");
427
428 const char* cpu_type = NULL;
429 const char* x64 = NULL;
430
431 if (is_intel()) {
432 cpu_type = "Intel";
433 x64 = cpu_is_em64t() ? " Intel64" : "";
434 } else if (is_amd()) {
435 cpu_type = "AMD";
436 x64 = cpu_is_em64t() ? " AMD64" : "";
437 } else if (is_hygon()) {
438 cpu_type = "Hygon";
439 x64 = cpu_is_em64t() ? " AMD64" : "";
440 } else {
441 cpu_type = "Unknown x86";
442 x64 = cpu_is_em64t() ? " x86_64" : "";
443 }
444
445 jio_snprintf(buf, buf_len, "%s %s%s SSE SSE2%s%s%s%s%s%s%s%s",
446 cpu_type,
447 cpu_family_description(),
448 supports_ht() ? " (HT)" : "",
449 supports_sse3() ? " SSE3" : "",
450 supports_ssse3() ? " SSSE3" : "",
451 supports_sse4_1() ? " SSE4.1" : "",
452 supports_sse4_2() ? " SSE4.2" : "",
453 supports_sse4a() ? " SSE4A" : "",
454 is_netburst() ? " Netburst" : "",
455 is_intel_family_core() ? " Core" : "",
456 x64);
457
458 return OS_OK;
459}
460
461int VM_Version_Ext::cpu_extended_brand_string(char* const buf, size_t buf_len) {
462 assert(buf != NULL, "buffer is NULL!");
463 assert(buf_len >= CPU_EBS_MAX_LENGTH, "buffer len should at least be == CPU_EBS_MAX_LENGTH!");
464 assert(getCPUIDBrandString_stub != NULL, "not initialized");
465
466 // invoke newly generated asm code to fetch CPU Brand String
467 getCPUIDBrandString_stub(&_cpuid_info);
468
469 // fetch results into buffer
470 *((uint32_t*) &buf[0]) = _cpuid_info.proc_name_0;
471 *((uint32_t*) &buf[4]) = _cpuid_info.proc_name_1;
472 *((uint32_t*) &buf[8]) = _cpuid_info.proc_name_2;
473 *((uint32_t*) &buf[12]) = _cpuid_info.proc_name_3;
474 *((uint32_t*) &buf[16]) = _cpuid_info.proc_name_4;
475 *((uint32_t*) &buf[20]) = _cpuid_info.proc_name_5;
476 *((uint32_t*) &buf[24]) = _cpuid_info.proc_name_6;
477 *((uint32_t*) &buf[28]) = _cpuid_info.proc_name_7;
478 *((uint32_t*) &buf[32]) = _cpuid_info.proc_name_8;
479 *((uint32_t*) &buf[36]) = _cpuid_info.proc_name_9;
480 *((uint32_t*) &buf[40]) = _cpuid_info.proc_name_10;
481 *((uint32_t*) &buf[44]) = _cpuid_info.proc_name_11;
482
483 return OS_OK;
484}
485
486size_t VM_Version_Ext::cpu_write_support_string(char* const buf, size_t buf_len) {
487 guarantee(buf != NULL, "buffer is NULL!");
488 guarantee(buf_len > 0, "buffer len not enough!");
489
490 unsigned int flag = 0;
491 unsigned int fi = 0;
492 size_t written = 0;
493 const char* prefix = "";
494
495#define WRITE_TO_BUF(string) \
496 { \
497 int res = jio_snprintf(&buf[written], buf_len - written, "%s%s", prefix, string); \
498 if (res < 0) { \
499 return buf_len - 1; \
500 } \
501 written += res; \
502 if (prefix[0] == '\0') { \
503 prefix = ", "; \
504 } \
505 }
506
507 for (flag = 1, fi = 0; flag <= 0x20000000 ; flag <<= 1, fi++) {
508 if (flag == HTT_FLAG && (((_cpuid_info.std_cpuid1_ebx.value >> 16) & 0xff) <= 1)) {
509 continue; /* no hyperthreading */
510 } else if (flag == SEP_FLAG && (cpu_family() == CPU_FAMILY_PENTIUMPRO && ((_cpuid_info.std_cpuid1_eax.value & 0xff) < 0x33))) {
511 continue; /* no fast system call */
512 }
513 if ((_cpuid_info.std_cpuid1_edx.value & flag) && strlen(_feature_edx_id[fi]) > 0) {
514 WRITE_TO_BUF(_feature_edx_id[fi]);
515 }
516 }
517
518 for (flag = 1, fi = 0; flag <= 0x20000000; flag <<= 1, fi++) {
519 if ((_cpuid_info.std_cpuid1_ecx.value & flag) && strlen(_feature_ecx_id[fi]) > 0) {
520 WRITE_TO_BUF(_feature_ecx_id[fi]);
521 }
522 }
523
524 for (flag = 1, fi = 0; flag <= 0x20000000 ; flag <<= 1, fi++) {
525 if ((_cpuid_info.ext_cpuid1_ecx.value & flag) && strlen(_feature_extended_ecx_id[fi]) > 0) {
526 WRITE_TO_BUF(_feature_extended_ecx_id[fi]);
527 }
528 }
529
530 for (flag = 1, fi = 0; flag <= 0x20000000; flag <<= 1, fi++) {
531 if ((_cpuid_info.ext_cpuid1_edx.value & flag) && strlen(_feature_extended_edx_id[fi]) > 0) {
532 WRITE_TO_BUF(_feature_extended_edx_id[fi]);
533 }
534 }
535
536 if (supports_tscinv_bit()) {
537 WRITE_TO_BUF("Invariant TSC");
538 }
539
540 return written;
541}
542
543/**
544 * Write a detailed description of the cpu to a given buffer, including
545 * feature set.
546 */
547int VM_Version_Ext::cpu_detailed_description(char* const buf, size_t buf_len) {
548 assert(buf != NULL, "buffer is NULL!");
549 assert(buf_len >= CPU_DETAILED_DESC_BUF_SIZE, "buffer len should at least be == CPU_DETAILED_DESC_BUF_SIZE!");
550
551 static const char* unknown = "<unknown>";
552 char vendor_id[VENDOR_LENGTH];
553 const char* family = NULL;
554 const char* model = NULL;
555 const char* brand = NULL;
556 int outputLen = 0;
557
558 family = cpu_family_description();
559 if (family == NULL) {
560 family = unknown;
561 }
562
563 model = cpu_model_description();
564 if (model == NULL) {
565 model = unknown;
566 }
567
568 brand = cpu_brand_string();
569
570 if (brand == NULL) {
571 brand = cpu_brand();
572 if (brand == NULL) {
573 brand = unknown;
574 }
575 }
576
577 *((uint32_t*) &vendor_id[0]) = _cpuid_info.std_vendor_name_0;
578 *((uint32_t*) &vendor_id[4]) = _cpuid_info.std_vendor_name_2;
579 *((uint32_t*) &vendor_id[8]) = _cpuid_info.std_vendor_name_1;
580 vendor_id[VENDOR_LENGTH-1] = '\0';
581
582 outputLen = jio_snprintf(buf, buf_len, "Brand: %s, Vendor: %s\n"
583 "Family: %s (0x%x), Model: %s (0x%x), Stepping: 0x%x\n"
584 "Ext. family: 0x%x, Ext. model: 0x%x, Type: 0x%x, Signature: 0x%8.8x\n"
585 "Features: ebx: 0x%8.8x, ecx: 0x%8.8x, edx: 0x%8.8x\n"
586 "Ext. features: eax: 0x%8.8x, ebx: 0x%8.8x, ecx: 0x%8.8x, edx: 0x%8.8x\n"
587 "Supports: ",
588 brand,
589 vendor_id,
590 family,
591 extended_cpu_family(),
592 model,
593 extended_cpu_model(),
594 cpu_stepping(),
595 _cpuid_info.std_cpuid1_eax.bits.ext_family,
596 _cpuid_info.std_cpuid1_eax.bits.ext_model,
597 _cpuid_info.std_cpuid1_eax.bits.proc_type,
598 _cpuid_info.std_cpuid1_eax.value,
599 _cpuid_info.std_cpuid1_ebx.value,
600 _cpuid_info.std_cpuid1_ecx.value,
601 _cpuid_info.std_cpuid1_edx.value,
602 _cpuid_info.ext_cpuid1_eax,
603 _cpuid_info.ext_cpuid1_ebx,
604 _cpuid_info.ext_cpuid1_ecx,
605 _cpuid_info.ext_cpuid1_edx);
606
607 if (outputLen < 0 || (size_t) outputLen >= buf_len - 1) {
608 if (buf_len > 0) { buf[buf_len-1] = '\0'; }
609 return OS_ERR;
610 }
611
612 cpu_write_support_string(&buf[outputLen], buf_len - outputLen);
613
614 return OS_OK;
615}
616
617const char* VM_Version_Ext::cpu_name(void) {
618 char cpu_type_desc[CPU_TYPE_DESC_BUF_SIZE];
619 size_t cpu_desc_len = sizeof(cpu_type_desc);
620
621 cpu_type_description(cpu_type_desc, cpu_desc_len);
622 char* tmp = NEW_C_HEAP_ARRAY_RETURN_NULL(char, cpu_desc_len, mtTracing);
623 if (NULL == tmp) {
624 return NULL;
625 }
626 strncpy(tmp, cpu_type_desc, cpu_desc_len);
627 return tmp;
628}
629
630const char* VM_Version_Ext::cpu_description(void) {
631 char cpu_detailed_desc_buffer[CPU_DETAILED_DESC_BUF_SIZE];
632 size_t cpu_detailed_desc_len = sizeof(cpu_detailed_desc_buffer);
633
634 cpu_detailed_description(cpu_detailed_desc_buffer, cpu_detailed_desc_len);
635
636 char* tmp = NEW_C_HEAP_ARRAY_RETURN_NULL(char, cpu_detailed_desc_len, mtTracing);
637
638 if (NULL == tmp) {
639 return NULL;
640 }
641
642 strncpy(tmp, cpu_detailed_desc_buffer, cpu_detailed_desc_len);
643 return tmp;
644}
645
646/**
647 * See Intel Application note 485 (chapter 10) for details
648 * on frequency extraction from cpu brand string.
649 * http://www.intel.com/content/dam/www/public/us/en/documents/application-notes/processor-identification-cpuid-instruction-note.pdf
650 *
651 */
652jlong VM_Version_Ext::max_qualified_cpu_freq_from_brand_string(void) {
653 // get brand string
654 const char* const brand_string = cpu_brand_string();
655 if (brand_string == NULL) {
656 return 0;
657 }
658
659 const u8 MEGA = 1000000;
660 u8 multiplier = 0;
661 jlong frequency = 0;
662
663 // the frequency information in the cpu brand string
664 // is given in either of two formats "x.xxyHz" or "xxxxyHz",
665 // where y=M,G,T and x is digits
666 const char* Hz_location = strchr(brand_string, 'H');
667
668 if (Hz_location != NULL) {
669 if (*(Hz_location + 1) == 'z') {
670 // switch on y in "yHz"
671 switch(*(Hz_location - 1)) {
672 case 'M' :
673 // Set multiplier to frequency is in Hz
674 multiplier = MEGA;
675 break;
676 case 'G' :
677 multiplier = MEGA * 1000;
678 break;
679 case 'T' :
680 multiplier = MEGA * 1000 * 1000;
681 break;
682 }
683 }
684 }
685
686 if (multiplier > 0) {
687 // compute frequency (in Hz) from brand string
688 if (*(Hz_location - 4) == '.') { // if format is "x.xx"
689 frequency = (jlong)(*(Hz_location - 5) - '0') * (multiplier);
690 frequency += (jlong)(*(Hz_location - 3) - '0') * (multiplier / 10);
691 frequency += (jlong)(*(Hz_location - 2) - '0') * (multiplier / 100);
692 } else { // format is "xxxx"
693 frequency = (jlong)(*(Hz_location - 5) - '0') * 1000;
694 frequency += (jlong)(*(Hz_location - 4) - '0') * 100;
695 frequency += (jlong)(*(Hz_location - 3) - '0') * 10;
696 frequency += (jlong)(*(Hz_location - 2) - '0');
697 frequency *= multiplier;
698 }
699 }
700 return frequency;
701}
702
703
704jlong VM_Version_Ext::maximum_qualified_cpu_frequency(void) {
705 if (_max_qualified_cpu_frequency == 0) {
706 _max_qualified_cpu_frequency = max_qualified_cpu_freq_from_brand_string();
707 }
708 return _max_qualified_cpu_frequency;
709}
710
711const char* const VM_Version_Ext::_family_id_intel[ExtendedFamilyIdLength_INTEL] = {
712 "8086/8088",
713 "",
714 "286",
715 "386",
716 "486",
717 "Pentium",
718 "Pentium Pro", //or Pentium-M/Woodcrest depeding on model
719 "",
720 "",
721 "",
722 "",
723 "",
724 "",
725 "",
726 "",
727 "Pentium 4"
728};
729
730const char* const VM_Version_Ext::_family_id_amd[ExtendedFamilyIdLength_AMD] = {
731 "",
732 "",
733 "",
734 "",
735 "5x86",
736 "K5/K6",
737 "Athlon/AthlonXP",
738 "",
739 "",
740 "",
741 "",
742 "",
743 "",
744 "",
745 "",
746 "Opteron/Athlon64",
747 "Opteron QC/Phenom" // Barcelona et.al.
748 "",
749 "",
750 "",
751 "",
752 "",
753 "",
754 "Zen"
755};
756// Partially from Intel 64 and IA-32 Architecture Software Developer's Manual,
757// September 2013, Vol 3C Table 35-1
758const char* const VM_Version_Ext::_model_id_pentium_pro[] = {
759 "",
760 "Pentium Pro",
761 "",
762 "Pentium II model 3",
763 "",
764 "Pentium II model 5/Xeon/Celeron",
765 "Celeron",
766 "Pentium III/Pentium III Xeon",
767 "Pentium III/Pentium III Xeon",
768 "Pentium M model 9", // Yonah
769 "Pentium III, model A",
770 "Pentium III, model B",
771 "",
772 "Pentium M model D", // Dothan
773 "",
774 "Core 2", // 0xf Woodcrest/Conroe/Merom/Kentsfield/Clovertown
775 "",
776 "",
777 "",
778 "",
779 "",
780 "",
781 "Celeron", // 0x16 Celeron 65nm
782 "Core 2", // 0x17 Penryn / Harpertown
783 "",
784 "",
785 "Core i7", // 0x1A CPU_MODEL_NEHALEM_EP
786 "Atom", // 0x1B Z5xx series Silverthorn
787 "",
788 "Core 2", // 0x1D Dunnington (6-core)
789 "Nehalem", // 0x1E CPU_MODEL_NEHALEM
790 "",
791 "",
792 "",
793 "",
794 "",
795 "",
796 "Westmere", // 0x25 CPU_MODEL_WESTMERE
797 "",
798 "",
799 "", // 0x28
800 "",
801 "Sandy Bridge", // 0x2a "2nd Generation Intel Core i7, i5, i3"
802 "",
803 "Westmere-EP", // 0x2c CPU_MODEL_WESTMERE_EP
804 "Sandy Bridge-EP", // 0x2d CPU_MODEL_SANDYBRIDGE_EP
805 "Nehalem-EX", // 0x2e CPU_MODEL_NEHALEM_EX
806 "Westmere-EX", // 0x2f CPU_MODEL_WESTMERE_EX
807 "",
808 "",
809 "",
810 "",
811 "",
812 "",
813 "",
814 "",
815 "",
816 "",
817 "Ivy Bridge", // 0x3a
818 "",
819 "Haswell", // 0x3c "4th Generation Intel Core Processor"
820 "", // 0x3d "Next Generation Intel Core Processor"
821 "Ivy Bridge-EP", // 0x3e "Next Generation Intel Xeon Processor E7 Family"
822 "", // 0x3f "Future Generation Intel Xeon Processor"
823 "",
824 "",
825 "",
826 "",
827 "",
828 "Haswell", // 0x45 "4th Generation Intel Core Processor"
829 "Haswell", // 0x46 "4th Generation Intel Core Processor"
830 NULL
831};
832
833/* Brand ID is for back compability
834 * Newer CPUs uses the extended brand string */
835const char* const VM_Version_Ext::_brand_id[] = {
836 "",
837 "Celeron processor",
838 "Pentium III processor",
839 "Intel Pentium III Xeon processor",
840 "",
841 "",
842 "",
843 "",
844 "Intel Pentium 4 processor",
845 NULL
846};
847
848
849const char* const VM_Version_Ext::_feature_edx_id[] = {
850 "On-Chip FPU",
851 "Virtual Mode Extensions",
852 "Debugging Extensions",
853 "Page Size Extensions",
854 "Time Stamp Counter",
855 "Model Specific Registers",
856 "Physical Address Extension",
857 "Machine Check Exceptions",
858 "CMPXCHG8B Instruction",
859 "On-Chip APIC",
860 "",
861 "Fast System Call",
862 "Memory Type Range Registers",
863 "Page Global Enable",
864 "Machine Check Architecture",
865 "Conditional Mov Instruction",
866 "Page Attribute Table",
867 "36-bit Page Size Extension",
868 "Processor Serial Number",
869 "CLFLUSH Instruction",
870 "",
871 "Debug Trace Store feature",
872 "ACPI registers in MSR space",
873 "Intel Architecture MMX Technology",
874 "Fast Float Point Save and Restore",
875 "Streaming SIMD extensions",
876 "Streaming SIMD extensions 2",
877 "Self-Snoop",
878 "Hyper Threading",
879 "Thermal Monitor",
880 "",
881 "Pending Break Enable"
882};
883
884const char* const VM_Version_Ext::_feature_extended_edx_id[] = {
885 "",
886 "",
887 "",
888 "",
889 "",
890 "",
891 "",
892 "",
893 "",
894 "",
895 "",
896 "SYSCALL/SYSRET",
897 "",
898 "",
899 "",
900 "",
901 "",
902 "",
903 "",
904 "",
905 "Execute Disable Bit",
906 "",
907 "",
908 "",
909 "",
910 "",
911 "",
912 "RDTSCP",
913 "",
914 "Intel 64 Architecture",
915 "",
916 ""
917};
918
919const char* const VM_Version_Ext::_feature_ecx_id[] = {
920 "Streaming SIMD Extensions 3",
921 "PCLMULQDQ",
922 "64-bit DS Area",
923 "MONITOR/MWAIT instructions",
924 "CPL Qualified Debug Store",
925 "Virtual Machine Extensions",
926 "Safer Mode Extensions",
927 "Enhanced Intel SpeedStep technology",
928 "Thermal Monitor 2",
929 "Supplemental Streaming SIMD Extensions 3",
930 "L1 Context ID",
931 "",
932 "Fused Multiply-Add",
933 "CMPXCHG16B",
934 "xTPR Update Control",
935 "Perfmon and Debug Capability",
936 "",
937 "Process-context identifiers",
938 "Direct Cache Access",
939 "Streaming SIMD extensions 4.1",
940 "Streaming SIMD extensions 4.2",
941 "x2APIC",
942 "MOVBE",
943 "Popcount instruction",
944 "TSC-Deadline",
945 "AESNI",
946 "XSAVE",
947 "OSXSAVE",
948 "AVX",
949 "F16C",
950 "RDRAND",
951 ""
952};
953
954const char* const VM_Version_Ext::_feature_extended_ecx_id[] = {
955 "LAHF/SAHF instruction support",
956 "Core multi-processor leagacy mode",
957 "",
958 "",
959 "",
960 "Advanced Bit Manipulations: LZCNT",
961 "SSE4A: MOVNTSS, MOVNTSD, EXTRQ, INSERTQ",
962 "Misaligned SSE mode",
963 "",
964 "",
965 "",
966 "",
967 "",
968 "",
969 "",
970 "",
971 "",
972 "",
973 "",
974 "",
975 "",
976 "",
977 "",
978 "",
979 "",
980 "",
981 "",
982 "",
983 "",
984 "",
985 "",
986 ""
987};
988