/*
* Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "jvm.h"
#include "utilities/macros.hpp"
#include "asm/macroAssembler.hpp"
#include "asm/macroAssembler.inline.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/resourceArea.hpp"
#include "runtime/java.hpp"
#include "runtime/stubCodeGenerator.hpp"
#include "vm_version_ext_x86.hpp"
typedef enum {
CPU_FAMILY_8086_8088 = 0,
CPU_FAMILY_INTEL_286 = 2,
CPU_FAMILY_INTEL_386 = 3,
CPU_FAMILY_INTEL_486 = 4,
CPU_FAMILY_PENTIUM = 5,
CPU_FAMILY_PENTIUMPRO = 6, // Same family several models
CPU_FAMILY_PENTIUM_4 = 0xF
} FamilyFlag;
typedef enum {
RDTSCP_FLAG = 0x08000000, // bit 27
INTEL64_FLAG = 0x20000000 // bit 29
} _featureExtendedEdxFlag;
#define CPUID_STANDARD_FN 0x0
#define CPUID_STANDARD_FN_1 0x1
#define CPUID_STANDARD_FN_4 0x4
#define CPUID_STANDARD_FN_B 0xb
#define CPUID_EXTENDED_FN 0x80000000
#define CPUID_EXTENDED_FN_1 0x80000001
#define CPUID_EXTENDED_FN_2 0x80000002
#define CPUID_EXTENDED_FN_3 0x80000003
#define CPUID_EXTENDED_FN_4 0x80000004
#define CPUID_EXTENDED_FN_7 0x80000007
#define CPUID_EXTENDED_FN_8 0x80000008
typedef enum {
FPU_FLAG = 0x00000001,
VME_FLAG = 0x00000002,
DE_FLAG = 0x00000004,
PSE_FLAG = 0x00000008,
TSC_FLAG = 0x00000010,
MSR_FLAG = 0x00000020,
PAE_FLAG = 0x00000040,
MCE_FLAG = 0x00000080,
CX8_FLAG = 0x00000100,
APIC_FLAG = 0x00000200,
SEP_FLAG = 0x00000800,
MTRR_FLAG = 0x00001000,
PGE_FLAG = 0x00002000,
MCA_FLAG = 0x00004000,
CMOV_FLAG = 0x00008000,
PAT_FLAG = 0x00010000,
PSE36_FLAG = 0x00020000,
PSNUM_FLAG = 0x00040000,
CLFLUSH_FLAG = 0x00080000,
DTS_FLAG = 0x00200000,
ACPI_FLAG = 0x00400000,
MMX_FLAG = 0x00800000,
FXSR_FLAG = 0x01000000,
SSE_FLAG = 0x02000000,
SSE2_FLAG = 0x04000000,
SS_FLAG = 0x08000000,
HTT_FLAG = 0x10000000,
TM_FLAG = 0x20000000
} FeatureEdxFlag;
static BufferBlob* cpuid_brand_string_stub_blob;
static const int cpuid_brand_string_stub_size = 550;
extern "C" {
typedef void (*getCPUIDBrandString_stub_t)(void*);
}
static getCPUIDBrandString_stub_t getCPUIDBrandString_stub = NULL;
class VM_Version_Ext_StubGenerator: public StubCodeGenerator {
public:
VM_Version_Ext_StubGenerator(CodeBuffer *c) : StubCodeGenerator(c) {}
address generate_getCPUIDBrandString(void) {
// Flags to test CPU type.
const uint32_t HS_EFL_AC = 0x40000;
const uint32_t HS_EFL_ID = 0x200000;
// Values for when we don't have a CPUID instruction.
const int CPU_FAMILY_SHIFT = 8;
const uint32_t CPU_FAMILY_386 = (3 << CPU_FAMILY_SHIFT);
const uint32_t CPU_FAMILY_486 = (4 << CPU_FAMILY_SHIFT);
Label detect_486, cpu486, detect_586, done, ext_cpuid;
StubCodeMark mark(this, "VM_Version_Ext", "getCPUIDNameInfo_stub");
# define __ _masm->
address start = __ pc();
//
// void getCPUIDBrandString(VM_Version::CpuidInfo* cpuid_info);
//
// LP64: rcx and rdx are first and second argument registers on windows
__ push(rbp);
#ifdef _LP64
__ mov(rbp, c_rarg0); // cpuid_info address
#else
__ movptr(rbp, Address(rsp, 8)); // cpuid_info address
#endif
__ push(rbx);
__ push(rsi);
__ pushf(); // preserve rbx, and flags
__ pop(rax);
__ push(rax);
__ mov(rcx, rax);
//
// if we are unable to change the AC flag, we have a 386
//
__ xorl(rax, HS_EFL_AC);
__ push(rax);
__ popf();
__ pushf();
__ pop(rax);
__ cmpptr(rax, rcx);
__ jccb(Assembler::notEqual, detect_486);
__ movl(rax, CPU_FAMILY_386);
__ jmp(done);
//
// If we are unable to change the ID flag, we have a 486 which does
// not support the "cpuid" instruction.
//
__ bind(detect_486);
__ mov(rax, rcx);
__ xorl(rax, HS_EFL_ID);
__ push(rax);
__ popf();
__ pushf();
__ pop(rax);
__ cmpptr(rcx, rax);
__ jccb(Assembler::notEqual, detect_586);
__ bind(cpu486);
__ movl(rax, CPU_FAMILY_486);
__ jmp(done);
//
// At this point, we have a chip which supports the "cpuid" instruction
//
__ bind(detect_586);
__ xorl(rax, rax);
__ cpuid();
__ orl(rax, rax);
__ jcc(Assembler::equal, cpu486); // if cpuid doesn't support an input
// value of at least 1, we give up and
// assume a 486
//
// Extended cpuid(0x80000000) for processor brand string detection
//
__ bind(ext_cpuid);
__ movl(rax, CPUID_EXTENDED_FN);
__ cpuid();
__ cmpl(rax, CPUID_EXTENDED_FN_4);
__ jcc(Assembler::below, done);
//
// Extended cpuid(0x80000002) // first 16 bytes in brand string
//
__ movl(rax, CPUID_EXTENDED_FN_2);
__ cpuid();
__ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_0_offset())));
__ movl(Address(rsi, 0), rax);
__ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_1_offset())));
__ movl(Address(rsi, 0), rbx);
__ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_2_offset())));
__ movl(Address(rsi, 0), rcx);
__ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_3_offset())));
__ movl(Address(rsi,0), rdx);
//
// Extended cpuid(0x80000003) // next 16 bytes in brand string
//
__ movl(rax, CPUID_EXTENDED_FN_3);
__ cpuid();
__ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_4_offset())));
__ movl(Address(rsi, 0), rax);
__ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_5_offset())));
__ movl(Address(rsi, 0), rbx);
__ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_6_offset())));
__ movl(Address(rsi, 0), rcx);
__ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_7_offset())));
__ movl(Address(rsi,0), rdx);
//
// Extended cpuid(0x80000004) // last 16 bytes in brand string
//
__ movl(rax, CPUID_EXTENDED_FN_4);
__ cpuid();
__ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_8_offset())));
__ movl(Address(rsi, 0), rax);
__ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_9_offset())));
__ movl(Address(rsi, 0), rbx);
__ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_10_offset())));
__ movl(Address(rsi, 0), rcx);
__ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_11_offset())));
__ movl(Address(rsi,0), rdx);
//
// return
//
__ bind(done);
__ popf();
__ pop(rsi);
__ pop(rbx);
__ pop(rbp);
__ ret(0);
# undef __
return start;
};
};
// VM_Version_Ext statics
const size_t VM_Version_Ext::VENDOR_LENGTH = 13;
const size_t VM_Version_Ext::CPU_EBS_MAX_LENGTH = (3 * 4 * 4 + 1);
const size_t VM_Version_Ext::CPU_TYPE_DESC_BUF_SIZE = 256;
const size_t VM_Version_Ext::CPU_DETAILED_DESC_BUF_SIZE = 4096;
char* VM_Version_Ext::_cpu_brand_string = NULL;
jlong VM_Version_Ext::_max_qualified_cpu_frequency = 0;
int VM_Version_Ext::_no_of_threads = 0;
int VM_Version_Ext::_no_of_cores = 0;
int VM_Version_Ext::_no_of_packages = 0;
void VM_Version_Ext::initialize(void) {
ResourceMark rm;
cpuid_brand_string_stub_blob = BufferBlob::create("getCPUIDBrandString_stub", cpuid_brand_string_stub_size);
if (cpuid_brand_string_stub_blob == NULL) {
vm_exit_during_initialization("Unable to allocate getCPUIDBrandString_stub");
}
CodeBuffer c(cpuid_brand_string_stub_blob);
VM_Version_Ext_StubGenerator g(&c);
getCPUIDBrandString_stub = CAST_TO_FN_PTR(getCPUIDBrandString_stub_t,
g.generate_getCPUIDBrandString());
}
const char* VM_Version_Ext::cpu_model_description(void) {
uint32_t cpu_family = extended_cpu_family();
uint32_t cpu_model = extended_cpu_model();
const char* model = NULL;
if (cpu_family == CPU_FAMILY_PENTIUMPRO) {
for (uint32_t i = 0; i <= cpu_model; i++) {
model = _model_id_pentium_pro[i];
if (model == NULL) {
break;
}
}
}
return model;
}
const char* VM_Version_Ext::cpu_brand_string(void) {
if (_cpu_brand_string == NULL) {
_cpu_brand_string = NEW_C_HEAP_ARRAY_RETURN_NULL(char, CPU_EBS_MAX_LENGTH, mtInternal);
if (NULL == _cpu_brand_string) {
return NULL;
}
int ret_val = cpu_extended_brand_string(_cpu_brand_string, CPU_EBS_MAX_LENGTH);
if (ret_val != OS_OK) {
FREE_C_HEAP_ARRAY(char, _cpu_brand_string);
_cpu_brand_string = NULL;
}
}
return _cpu_brand_string;
}
const char* VM_Version_Ext::cpu_brand(void) {
const char* brand = NULL;
if ((_cpuid_info.std_cpuid1_ebx.value & 0xFF) > 0) {
int brand_num = _cpuid_info.std_cpuid1_ebx.value & 0xFF;
brand = _brand_id[0];
for (int i = 0; brand != NULL && i <= brand_num; i += 1) {
brand = _brand_id[i];
}
}
return brand;
}
bool VM_Version_Ext::cpu_is_em64t(void) {
return ((_cpuid_info.ext_cpuid1_edx.value & INTEL64_FLAG) == INTEL64_FLAG);
}
bool VM_Version_Ext::is_netburst(void) {
return (is_intel() && (extended_cpu_family() == CPU_FAMILY_PENTIUM_4));
}
bool VM_Version_Ext::supports_tscinv_ext(void) {
if (!supports_tscinv_bit()) {
return false;
}
if (is_intel()) {
return true;
}
if (is_amd()) {
return !is_amd_Barcelona();
}
if (is_hygon()) {
return true;
}
return false;
}
void VM_Version_Ext::resolve_cpu_information_details(void) {
// in future we want to base this information on proper cpu
// and cache topology enumeration such as:
// Intel 64 Architecture Processor Topology Enumeration
// which supports system cpu and cache topology enumeration
// either using 2xAPICIDs or initial APICIDs
// currently only rough cpu information estimates
// which will not necessarily reflect the exact configuration of the system
// this is the number of logical hardware threads
// visible to the operating system
_no_of_threads = os::processor_count();
// find out number of threads per cpu package
int threads_per_package = threads_per_core() * cores_per_cpu();
// use amount of threads visible to the process in order to guess number of sockets
_no_of_packages = _no_of_threads / threads_per_package;
// process might only see a subset of the total number of threads
// from a single processor package. Virtualization/resource management for example.
// If so then just write a hard 1 as num of pkgs.
if (0 == _no_of_packages) {
_no_of_packages = 1;
}
// estimate the number of cores
_no_of_cores = cores_per_cpu() * _no_of_packages;
}
int VM_Version_Ext::number_of_threads(void) {
if (_no_of_threads == 0) {
resolve_cpu_information_details();
}
return _no_of_threads;
}
int VM_Version_Ext::number_of_cores(void) {
if (_no_of_cores == 0) {
resolve_cpu_information_details();
}
return _no_of_cores;
}
int VM_Version_Ext::number_of_sockets(void) {
if (_no_of_packages == 0) {
resolve_cpu_information_details();
}
return _no_of_packages;
}
const char* VM_Version_Ext::cpu_family_description(void) {
int cpu_family_id = extended_cpu_family();
if (is_amd()) {
if (cpu_family_id < ExtendedFamilyIdLength_AMD) {
return _family_id_amd[cpu_family_id];
}
}
if (is_intel()) {
if (cpu_family_id == CPU_FAMILY_PENTIUMPRO) {
return cpu_model_description();
}
if (cpu_family_id < ExtendedFamilyIdLength_INTEL) {
return _family_id_intel[cpu_family_id];
}
}
if (is_hygon()) {
return "Dhyana";
}
return "Unknown x86";
}
int VM_Version_Ext::cpu_type_description(char* const buf, size_t buf_len) {
assert(buf != NULL, "buffer is NULL!");
assert(buf_len >= CPU_TYPE_DESC_BUF_SIZE, "buffer len should at least be == CPU_TYPE_DESC_BUF_SIZE!");
const char* cpu_type = NULL;
const char* x64 = NULL;
if (is_intel()) {
cpu_type = "Intel";
x64 = cpu_is_em64t() ? " Intel64" : "";
} else if (is_amd()) {
cpu_type = "AMD";
x64 = cpu_is_em64t() ? " AMD64" : "";
} else if (is_hygon()) {
cpu_type = "Hygon";
x64 = cpu_is_em64t() ? " AMD64" : "";
} else {
cpu_type = "Unknown x86";
x64 = cpu_is_em64t() ? " x86_64" : "";
}
jio_snprintf(buf, buf_len, "%s %s%s SSE SSE2%s%s%s%s%s%s%s%s",
cpu_type,
cpu_family_description(),
supports_ht() ? " (HT)" : "",
supports_sse3() ? " SSE3" : "",
supports_ssse3() ? " SSSE3" : "",
supports_sse4_1() ? " SSE4.1" : "",
supports_sse4_2() ? " SSE4.2" : "",
supports_sse4a() ? " SSE4A" : "",
is_netburst() ? " Netburst" : "",
is_intel_family_core() ? " Core" : "",
x64);
return OS_OK;
}
int VM_Version_Ext::cpu_extended_brand_string(char* const buf, size_t buf_len) {
assert(buf != NULL, "buffer is NULL!");
assert(buf_len >= CPU_EBS_MAX_LENGTH, "buffer len should at least be == CPU_EBS_MAX_LENGTH!");
assert(getCPUIDBrandString_stub != NULL, "not initialized");
// invoke newly generated asm code to fetch CPU Brand String
getCPUIDBrandString_stub(&_cpuid_info);
// fetch results into buffer
*((uint32_t*) &buf[0]) = _cpuid_info.proc_name_0;
*((uint32_t*) &buf[4]) = _cpuid_info.proc_name_1;
*((uint32_t*) &buf[8]) = _cpuid_info.proc_name_2;
*((uint32_t*) &buf[12]) = _cpuid_info.proc_name_3;
*((uint32_t*) &buf[16]) = _cpuid_info.proc_name_4;
*((uint32_t*) &buf[20]) = _cpuid_info.proc_name_5;
*((uint32_t*) &buf[24]) = _cpuid_info.proc_name_6;
*((uint32_t*) &buf[28]) = _cpuid_info.proc_name_7;
*((uint32_t*) &buf[32]) = _cpuid_info.proc_name_8;
*((uint32_t*) &buf[36]) = _cpuid_info.proc_name_9;
*((uint32_t*) &buf[40]) = _cpuid_info.proc_name_10;
*((uint32_t*) &buf[44]) = _cpuid_info.proc_name_11;
return OS_OK;
}
size_t VM_Version_Ext::cpu_write_support_string(char* const buf, size_t buf_len) {
guarantee(buf != NULL, "buffer is NULL!");
guarantee(buf_len > 0, "buffer len not enough!");
unsigned int flag = 0;
unsigned int fi = 0;
size_t written = 0;
const char* prefix = "";
#define WRITE_TO_BUF(string) \
{ \
int res = jio_snprintf(&buf[written], buf_len - written, "%s%s", prefix, string); \
if (res < 0) { \
return buf_len - 1; \
} \
written += res; \
if (prefix[0] == '\0') { \
prefix = ", "; \
} \
}
for (flag = 1, fi = 0; flag <= 0x20000000 ; flag <<= 1, fi++) {
if (flag == HTT_FLAG && (((_cpuid_info.std_cpuid1_ebx.value >> 16) & 0xff) <= 1)) {
continue; /* no hyperthreading */
} else if (flag == SEP_FLAG && (cpu_family() == CPU_FAMILY_PENTIUMPRO && ((_cpuid_info.std_cpuid1_eax.value & 0xff) < 0x33))) {
continue; /* no fast system call */
}
if ((_cpuid_info.std_cpuid1_edx.value & flag) && strlen(_feature_edx_id[fi]) > 0) {
WRITE_TO_BUF(_feature_edx_id[fi]);
}
}
for (flag = 1, fi = 0; flag <= 0x20000000; flag <<= 1, fi++) {
if ((_cpuid_info.std_cpuid1_ecx.value & flag) && strlen(_feature_ecx_id[fi]) > 0) {
WRITE_TO_BUF(_feature_ecx_id[fi]);
}
}
for (flag = 1, fi = 0; flag <= 0x20000000 ; flag <<= 1, fi++) {
if ((_cpuid_info.ext_cpuid1_ecx.value & flag) && strlen(_feature_extended_ecx_id[fi]) > 0) {
WRITE_TO_BUF(_feature_extended_ecx_id[fi]);
}
}
for (flag = 1, fi = 0; flag <= 0x20000000; flag <<= 1, fi++) {
if ((_cpuid_info.ext_cpuid1_edx.value & flag) && strlen(_feature_extended_edx_id[fi]) > 0) {
WRITE_TO_BUF(_feature_extended_edx_id[fi]);
}
}
if (supports_tscinv_bit()) {
WRITE_TO_BUF("Invariant TSC");
}
return written;
}
/**
* Write a detailed description of the cpu to a given buffer, including
* feature set.
*/
int VM_Version_Ext::cpu_detailed_description(char* const buf, size_t buf_len) {
assert(buf != NULL, "buffer is NULL!");
assert(buf_len >= CPU_DETAILED_DESC_BUF_SIZE, "buffer len should at least be == CPU_DETAILED_DESC_BUF_SIZE!");
static const char* unknown = "<unknown>";
char vendor_id[VENDOR_LENGTH];
const char* family = NULL;
const char* model = NULL;
const char* brand = NULL;
int outputLen = 0;
family = cpu_family_description();
if (family == NULL) {
family = unknown;
}
model = cpu_model_description();
if (model == NULL) {
model = unknown;
}
brand = cpu_brand_string();
if (brand == NULL) {
brand = cpu_brand();
if (brand == NULL) {
brand = unknown;
}
}
*((uint32_t*) &vendor_id[0]) = _cpuid_info.std_vendor_name_0;
*((uint32_t*) &vendor_id[4]) = _cpuid_info.std_vendor_name_2;
*((uint32_t*) &vendor_id[8]) = _cpuid_info.std_vendor_name_1;
vendor_id[VENDOR_LENGTH-1] = '\0';
outputLen = jio_snprintf(buf, buf_len, "Brand: %s, Vendor: %s\n"
"Family: %s (0x%x), Model: %s (0x%x), Stepping: 0x%x\n"
"Ext. family: 0x%x, Ext. model: 0x%x, Type: 0x%x, Signature: 0x%8.8x\n"
"Features: ebx: 0x%8.8x, ecx: 0x%8.8x, edx: 0x%8.8x\n"
"Ext. features: eax: 0x%8.8x, ebx: 0x%8.8x, ecx: 0x%8.8x, edx: 0x%8.8x\n"
"Supports: ",
brand,
vendor_id,
family,
extended_cpu_family(),
model,
extended_cpu_model(),
cpu_stepping(),
_cpuid_info.std_cpuid1_eax.bits.ext_family,
_cpuid_info.std_cpuid1_eax.bits.ext_model,
_cpuid_info.std_cpuid1_eax.bits.proc_type,
_cpuid_info.std_cpuid1_eax.value,
_cpuid_info.std_cpuid1_ebx.value,
_cpuid_info.std_cpuid1_ecx.value,
_cpuid_info.std_cpuid1_edx.value,
_cpuid_info.ext_cpuid1_eax,
_cpuid_info.ext_cpuid1_ebx,
_cpuid_info.ext_cpuid1_ecx,
_cpuid_info.ext_cpuid1_edx);
if (outputLen < 0 || (size_t) outputLen >= buf_len - 1) {
if (buf_len > 0) { buf[buf_len-1] = '\0'; }
return OS_ERR;
}
cpu_write_support_string(&buf[outputLen], buf_len - outputLen);
return OS_OK;
}
const char* VM_Version_Ext::cpu_name(void) {
char cpu_type_desc[CPU_TYPE_DESC_BUF_SIZE];
size_t cpu_desc_len = sizeof(cpu_type_desc);
cpu_type_description(cpu_type_desc, cpu_desc_len);
char* tmp = NEW_C_HEAP_ARRAY_RETURN_NULL(char, cpu_desc_len, mtTracing);
if (NULL == tmp) {
return NULL;
}
strncpy(tmp, cpu_type_desc, cpu_desc_len);
return tmp;
}
const char* VM_Version_Ext::cpu_description(void) {
char cpu_detailed_desc_buffer[CPU_DETAILED_DESC_BUF_SIZE];
size_t cpu_detailed_desc_len = sizeof(cpu_detailed_desc_buffer);
cpu_detailed_description(cpu_detailed_desc_buffer, cpu_detailed_desc_len);
char* tmp = NEW_C_HEAP_ARRAY_RETURN_NULL(char, cpu_detailed_desc_len, mtTracing);
if (NULL == tmp) {
return NULL;
}
strncpy(tmp, cpu_detailed_desc_buffer, cpu_detailed_desc_len);
return tmp;
}
/**
* See Intel Application note 485 (chapter 10) for details
* on frequency extraction from cpu brand string.
* http://www.intel.com/content/dam/www/public/us/en/documents/application-notes/processor-identification-cpuid-instruction-note.pdf
*
*/
jlong VM_Version_Ext::max_qualified_cpu_freq_from_brand_string(void) {
// get brand string
const char* const brand_string = cpu_brand_string();
if (brand_string == NULL) {
return 0;
}
const u8 MEGA = 1000000;
u8 multiplier = 0;
jlong frequency = 0;
// the frequency information in the cpu brand string
// is given in either of two formats "x.xxyHz" or "xxxxyHz",
// where y=M,G,T and x is digits
const char* Hz_location = strchr(brand_string, 'H');
if (Hz_location != NULL) {
if (*(Hz_location + 1) == 'z') {
// switch on y in "yHz"
switch(*(Hz_location - 1)) {
case 'M' :
// Set multiplier to frequency is in Hz
multiplier = MEGA;
break;
case 'G' :
multiplier = MEGA * 1000;
break;
case 'T' :
multiplier = MEGA * 1000 * 1000;
break;
}
}
}
if (multiplier > 0) {
// compute frequency (in Hz) from brand string
if (*(Hz_location - 4) == '.') { // if format is "x.xx"
frequency = (jlong)(*(Hz_location - 5) - '0') * (multiplier);
frequency += (jlong)(*(Hz_location - 3) - '0') * (multiplier / 10);
frequency += (jlong)(*(Hz_location - 2) - '0') * (multiplier / 100);
} else { // format is "xxxx"
frequency = (jlong)(*(Hz_location - 5) - '0') * 1000;
frequency += (jlong)(*(Hz_location - 4) - '0') * 100;
frequency += (jlong)(*(Hz_location - 3) - '0') * 10;
frequency += (jlong)(*(Hz_location - 2) - '0');
frequency *= multiplier;
}
}
return frequency;
}
jlong VM_Version_Ext::maximum_qualified_cpu_frequency(void) {
if (_max_qualified_cpu_frequency == 0) {
_max_qualified_cpu_frequency = max_qualified_cpu_freq_from_brand_string();
}
return _max_qualified_cpu_frequency;
}
const char* const VM_Version_Ext::_family_id_intel[ExtendedFamilyIdLength_INTEL] = {
"8086/8088",
"",
"286",
"386",
"486",
"Pentium",
"Pentium Pro", //or Pentium-M/Woodcrest depeding on model
"",
"",
"",
"",
"",
"",
"",
"",
"Pentium 4"
};
const char* const VM_Version_Ext::_family_id_amd[ExtendedFamilyIdLength_AMD] = {
"",
"",
"",
"",
"5x86",
"K5/K6",
"Athlon/AthlonXP",
"",
"",
"",
"",
"",
"",
"",
"",
"Opteron/Athlon64",
"Opteron QC/Phenom" // Barcelona et.al.
"",
"",
"",
"",
"",
"",
"Zen"
};
// Partially from Intel 64 and IA-32 Architecture Software Developer's Manual,
// September 2013, Vol 3C Table 35-1
const char* const VM_Version_Ext::_model_id_pentium_pro[] = {
"",
"Pentium Pro",
"",
"Pentium II model 3",
"",
"Pentium II model 5/Xeon/Celeron",
"Celeron",
"Pentium III/Pentium III Xeon",
"Pentium III/Pentium III Xeon",
"Pentium M model 9", // Yonah
"Pentium III, model A",
"Pentium III, model B",
"",
"Pentium M model D", // Dothan
"",
"Core 2", // 0xf Woodcrest/Conroe/Merom/Kentsfield/Clovertown
"",
"",
"",
"",
"",
"",
"Celeron", // 0x16 Celeron 65nm
"Core 2", // 0x17 Penryn / Harpertown
"",
"",
"Core i7", // 0x1A CPU_MODEL_NEHALEM_EP
"Atom", // 0x1B Z5xx series Silverthorn
"",
"Core 2", // 0x1D Dunnington (6-core)
"Nehalem", // 0x1E CPU_MODEL_NEHALEM
"",
"",
"",
"",
"",
"",
"Westmere", // 0x25 CPU_MODEL_WESTMERE
"",
"",
"", // 0x28
"",
"Sandy Bridge", // 0x2a "2nd Generation Intel Core i7, i5, i3"
"",
"Westmere-EP", // 0x2c CPU_MODEL_WESTMERE_EP
"Sandy Bridge-EP", // 0x2d CPU_MODEL_SANDYBRIDGE_EP
"Nehalem-EX", // 0x2e CPU_MODEL_NEHALEM_EX
"Westmere-EX", // 0x2f CPU_MODEL_WESTMERE_EX
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"Ivy Bridge", // 0x3a
"",
"Haswell", // 0x3c "4th Generation Intel Core Processor"
"", // 0x3d "Next Generation Intel Core Processor"
"Ivy Bridge-EP", // 0x3e "Next Generation Intel Xeon Processor E7 Family"
"", // 0x3f "Future Generation Intel Xeon Processor"
"",
"",
"",
"",
"",
"Haswell", // 0x45 "4th Generation Intel Core Processor"
/**代码未完, 请加载全部代码(NowJava.com).**/