author | jlahoda |
Tue, 24 Sep 2019 15:40:26 +0200 | |
branch | JDK-8226585-branch |
changeset 58290 | d885633d9de4 |
parent 54529 | d2c2622995e2 |
permissions | -rw-r--r-- |
50113 | 1 |
/* |
54519 | 2 |
* Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved. |
50113 | 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 |
||
36 |
typedef 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 |
||
54529
d2c2622995e2
8222387: Out-of-bounds access to CPU _family_id_xxx array
dholmes
parents:
54519
diff
changeset
|
46 |
typedef enum { |
d2c2622995e2
8222387: Out-of-bounds access to CPU _family_id_xxx array
dholmes
parents:
54519
diff
changeset
|
47 |
RDTSCP_FLAG = 0x08000000, // bit 27 |
d2c2622995e2
8222387: Out-of-bounds access to CPU _family_id_xxx array
dholmes
parents:
54519
diff
changeset
|
48 |
INTEL64_FLAG = 0x20000000 // bit 29 |
d2c2622995e2
8222387: Out-of-bounds access to CPU _family_id_xxx array
dholmes
parents:
54519
diff
changeset
|
49 |
} _featureExtendedEdxFlag; |
50113 | 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 |
||
64 |
typedef 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 |
||
95 |
static BufferBlob* cpuid_brand_string_stub_blob; |
|
96 |
static const int cpuid_brand_string_stub_size = 550; |
|
97 |
||
98 |
extern "C" { |
|
99 |
typedef void (*getCPUIDBrandString_stub_t)(void*); |
|
100 |
} |
|
101 |
||
102 |
static getCPUIDBrandString_stub_t getCPUIDBrandString_stub = NULL; |
|
103 |
||
104 |
class 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 |
|
254 |
const size_t VM_Version_Ext::VENDOR_LENGTH = 13; |
|
255 |
const size_t VM_Version_Ext::CPU_EBS_MAX_LENGTH = (3 * 4 * 4 + 1); |
|
256 |
const size_t VM_Version_Ext::CPU_TYPE_DESC_BUF_SIZE = 256; |
|
257 |
const size_t VM_Version_Ext::CPU_DETAILED_DESC_BUF_SIZE = 4096; |
|
258 |
char* VM_Version_Ext::_cpu_brand_string = NULL; |
|
259 |
jlong VM_Version_Ext::_max_qualified_cpu_frequency = 0; |
|
260 |
||
261 |
int VM_Version_Ext::_no_of_threads = 0; |
|
262 |
int VM_Version_Ext::_no_of_cores = 0; |
|
263 |
int VM_Version_Ext::_no_of_packages = 0; |
|
264 |
||
265 |
void 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 |
||
278 |
const 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 |
||
294 |
const 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 |
||
309 |
const 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 |
||
322 |
bool VM_Version_Ext::cpu_is_em64t(void) { |
|
323 |
return ((_cpuid_info.ext_cpuid1_edx.value & INTEL64_FLAG) == INTEL64_FLAG); |
|
324 |
} |
|
325 |
||
326 |
bool VM_Version_Ext::is_netburst(void) { |
|
327 |
return (is_intel() && (extended_cpu_family() == CPU_FAMILY_PENTIUM_4)); |
|
328 |
} |
|
329 |
||
330 |
bool 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 |
||
54519 | 343 |
if (is_hygon()) { |
344 |
return true; |
|
345 |
} |
|
346 |
||
50113 | 347 |
return false; |
348 |
} |
|
349 |
||
350 |
void 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 |
||
382 |
int 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 |
||
389 |
int 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 |
||
396 |
int 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 |
||
403 |
const char* VM_Version_Ext::cpu_family_description(void) { |
|
404 |
int cpu_family_id = extended_cpu_family(); |
|
405 |
if (is_amd()) { |
|
54529
d2c2622995e2
8222387: Out-of-bounds access to CPU _family_id_xxx array
dholmes
parents:
54519
diff
changeset
|
406 |
if (cpu_family_id < ExtendedFamilyIdLength_AMD) { |
d2c2622995e2
8222387: Out-of-bounds access to CPU _family_id_xxx array
dholmes
parents:
54519
diff
changeset
|
407 |
return _family_id_amd[cpu_family_id]; |
d2c2622995e2
8222387: Out-of-bounds access to CPU _family_id_xxx array
dholmes
parents:
54519
diff
changeset
|
408 |
} |
50113 | 409 |
} |
410 |
if (is_intel()) { |
|
411 |
if (cpu_family_id == CPU_FAMILY_PENTIUMPRO) { |
|
412 |
return cpu_model_description(); |
|
413 |
} |
|
54529
d2c2622995e2
8222387: Out-of-bounds access to CPU _family_id_xxx array
dholmes
parents:
54519
diff
changeset
|
414 |
if (cpu_family_id < ExtendedFamilyIdLength_INTEL) { |
d2c2622995e2
8222387: Out-of-bounds access to CPU _family_id_xxx array
dholmes
parents:
54519
diff
changeset
|
415 |
return _family_id_intel[cpu_family_id]; |
d2c2622995e2
8222387: Out-of-bounds access to CPU _family_id_xxx array
dholmes
parents:
54519
diff
changeset
|
416 |
} |
50113 | 417 |
} |
54519 | 418 |
if (is_hygon()) { |
419 |
return "Dhyana"; |
|
420 |
} |
|
50113 | 421 |
return "Unknown x86"; |
422 |
} |
|
423 |
||
424 |
int 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" : ""; |
|
54519 | 437 |
} else if (is_hygon()) { |
438 |
cpu_type = "Hygon"; |
|
439 |
x64 = cpu_is_em64t() ? " AMD64" : ""; |
|
50113 | 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 |
||
461 |
int 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 |
||
486 |
size_t VM_Version_Ext::cpu_write_support_string(char* const buf, size_t buf_len) { |
|
51070 | 487 |
guarantee(buf != NULL, "buffer is NULL!"); |
488 |
guarantee(buf_len > 0, "buffer len not enough!"); |
|
50113 | 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); \ |
|
51070 | 498 |
if (res < 0) { \ |
50113 | 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 |
*/ |
|
547 |
int 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) { |
|
51070 | 608 |
if (buf_len > 0) { buf[buf_len-1] = '\0'; } |
50113 | 609 |
return OS_ERR; |
610 |
} |
|
611 |
||
612 |
cpu_write_support_string(&buf[outputLen], buf_len - outputLen); |
|
613 |
||
614 |
return OS_OK; |
|
615 |
} |
|
616 |
||
617 |
const 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 |
||
630 |
const 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 |
*/ |
|
652 |
jlong 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 |
||
704 |
jlong 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 |
||
54529
d2c2622995e2
8222387: Out-of-bounds access to CPU _family_id_xxx array
dholmes
parents:
54519
diff
changeset
|
711 |
const char* const VM_Version_Ext::_family_id_intel[ExtendedFamilyIdLength_INTEL] = { |
50113 | 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 |
||
54529
d2c2622995e2
8222387: Out-of-bounds access to CPU _family_id_xxx array
dholmes
parents:
54519
diff
changeset
|
730 |
const char* const VM_Version_Ext::_family_id_amd[ExtendedFamilyIdLength_AMD] = { |
50113 | 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. |
|
54529
d2c2622995e2
8222387: Out-of-bounds access to CPU _family_id_xxx array
dholmes
parents:
54519
diff
changeset
|
748 |
"", |
d2c2622995e2
8222387: Out-of-bounds access to CPU _family_id_xxx array
dholmes
parents:
54519
diff
changeset
|
749 |
"", |
d2c2622995e2
8222387: Out-of-bounds access to CPU _family_id_xxx array
dholmes
parents:
54519
diff
changeset
|
750 |
"", |
d2c2622995e2
8222387: Out-of-bounds access to CPU _family_id_xxx array
dholmes
parents:
54519
diff
changeset
|
751 |
"", |
d2c2622995e2
8222387: Out-of-bounds access to CPU _family_id_xxx array
dholmes
parents:
54519
diff
changeset
|
752 |
"", |
d2c2622995e2
8222387: Out-of-bounds access to CPU _family_id_xxx array
dholmes
parents:
54519
diff
changeset
|
753 |
"", |
d2c2622995e2
8222387: Out-of-bounds access to CPU _family_id_xxx array
dholmes
parents:
54519
diff
changeset
|
754 |
"Zen" |
50113 | 755 |
}; |
756 |
// Partially from Intel 64 and IA-32 Architecture Software Developer's Manual, |
|
757 |
// September 2013, Vol 3C Table 35-1 |
|
758 |
const 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 */ |
|
835 |
const 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 |
||
849 |
const 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 |
||
884 |
const 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 |
||
919 |
const 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 |
||
954 |
const 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 |
}; |