1// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "vm/globals.h"
6#if !defined(HOST_OS_MACOS)
7#include "vm/cpuid.h"
8
9#if defined(HOST_ARCH_IA32) || defined(HOST_ARCH_X64)
10// GetCpuId() on Windows, __get_cpuid() on Linux
11#if defined(HOST_OS_WINDOWS)
12#include <intrin.h> // NOLINT
13#else
14#include <cpuid.h> // NOLINT
15#endif
16#endif
17
18namespace dart {
19
20bool CpuId::sse2_ = false;
21bool CpuId::sse41_ = false;
22bool CpuId::popcnt_ = false;
23bool CpuId::abm_ = false;
24
25const char* CpuId::id_string_ = nullptr;
26const char* CpuId::brand_string_ = nullptr;
27
28#if defined(HOST_ARCH_IA32) || defined(HOST_ARCH_X64)
29
30void CpuId::GetCpuId(int32_t level, uint32_t info[4]) {
31#if defined(HOST_OS_WINDOWS)
32 // The documentation for __cpuid is at:
33 // http://msdn.microsoft.com/en-us/library/hskdteyh(v=vs.90).aspx
34 __cpuid(reinterpret_cast<int*>(info), level);
35#else
36 __get_cpuid(level, &info[0], &info[1], &info[2], &info[3]);
37#endif
38}
39
40void CpuId::Init() {
41 uint32_t info[4] = {static_cast<uint32_t>(-1)};
42
43 GetCpuId(0, info);
44 char* id_string = reinterpret_cast<char*>(malloc(3 * sizeof(int32_t)));
45
46 // Yes, these are supposed to be out of order.
47 *reinterpret_cast<uint32_t*>(id_string) = info[1];
48 *reinterpret_cast<uint32_t*>(id_string + 4) = info[3];
49 *reinterpret_cast<uint32_t*>(id_string + 8) = info[2];
50 CpuId::id_string_ = id_string;
51
52 GetCpuId(1, info);
53 CpuId::sse41_ = (info[2] & (1 << 19)) != 0;
54 CpuId::sse2_ = (info[3] & (1 << 26)) != 0;
55 CpuId::popcnt_ = (info[2] & (1 << 23)) != 0;
56
57 GetCpuId(0x80000001, info);
58 CpuId::abm_ = (info[2] & (1 << 5)) != 0;
59
60 char* brand_string =
61 reinterpret_cast<char*>(malloc(3 * 4 * sizeof(uint32_t)));
62 for (uint32_t i = 0x80000002; i <= 0x80000004; i++) {
63 uint32_t off = (i - 0x80000002U) * 4 * sizeof(uint32_t);
64 GetCpuId(i, info);
65 *reinterpret_cast<int32_t*>(brand_string + off) = info[0];
66 *reinterpret_cast<int32_t*>(brand_string + off + 4) = info[1];
67 *reinterpret_cast<int32_t*>(brand_string + off + 8) = info[2];
68 *reinterpret_cast<int32_t*>(brand_string + off + 12) = info[3];
69 }
70 CpuId::brand_string_ = brand_string;
71}
72
73void CpuId::Cleanup() {
74 ASSERT(id_string_ != NULL);
75 free(const_cast<char*>(id_string_));
76 id_string_ = NULL;
77
78 ASSERT(brand_string_ != NULL);
79 free(const_cast<char*>(brand_string_));
80 brand_string_ = NULL;
81}
82
83const char* CpuId::id_string() {
84 return Utils::StrDup(id_string_);
85}
86
87const char* CpuId::brand_string() {
88 return Utils::StrDup(brand_string_);
89}
90
91const char* CpuId::field(CpuInfoIndices idx) {
92 switch (idx) {
93 case kCpuInfoProcessor:
94 return id_string();
95 case kCpuInfoModel:
96 return brand_string();
97 case kCpuInfoHardware:
98 return brand_string();
99 case kCpuInfoFeatures: {
100 char buffer[100];
101 char* p = buffer;
102 const char* q = p + 100;
103 *p = '\0';
104 if (sse2()) {
105 p += snprintf(p, q - p, "sse2 ");
106 }
107 if (sse41()) {
108 p += snprintf(p, q - p, "sse4.1 ");
109 }
110 if (popcnt()) {
111 p += snprintf(p, q - p, "popcnt ");
112 }
113 if (abm()) {
114 p += snprintf(p, q - p, "abm ");
115 }
116 // Remove last space before returning string.
117 if (p != buffer) *(p - 1) = '\0';
118 return Utils::StrDup(buffer);
119 }
120 default: {
121 UNREACHABLE();
122 return NULL;
123 }
124 }
125}
126
127#endif // defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
128} // namespace dart
129
130#endif // !defined(HOST_OS_MACOS)
131