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(DART_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(DART_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
30static void GetCpuId(int32_t level, uint32_t info[4]) {
31#if defined(DART_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(leaf: level, eax: &info[0], ebx: &info[1], ecx: &info[2], edx: &info[3]);
37#endif
38}
39
40void CpuId::Init() {
41 uint32_t info[4] = {static_cast<uint32_t>(-1)};
42
43 GetCpuId(level: 0, info);
44 char* id_string = reinterpret_cast<char*>(malloc(size: 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(level: 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(level: 0x80000001, info);
58 CpuId::abm_ = (info[2] & (1 << 5)) != 0;
59
60 // Brand string returned by CPUID is expected to be nullptr-terminated,
61 // however we have seen cases in the wild which violate this assumption.
62 // To avoid going out of bounds when trying to print this string
63 // we add null-terminator ourselves, just in case.
64 //
65 // See https://github.com/flutter/flutter/issues/114346
66 char* brand_string = reinterpret_cast<char*>(calloc(n: 3 * sizeof(info) + 1, size: 1));
67 for (uint32_t i = 0; i < 2; i++) {
68 GetCpuId(level: 0x80000002U + i, info);
69 memmove(dest: &brand_string[i * sizeof(info)], src: &info, n: sizeof(info));
70 }
71 CpuId::brand_string_ = brand_string;
72}
73
74void CpuId::Cleanup() {
75 ASSERT(id_string_ != nullptr);
76 free(ptr: const_cast<char*>(id_string_));
77 id_string_ = nullptr;
78
79 ASSERT(brand_string_ != nullptr);
80 free(ptr: const_cast<char*>(brand_string_));
81 brand_string_ = nullptr;
82}
83
84const char* CpuId::id_string() {
85 return Utils::StrDup(s: id_string_);
86}
87
88const char* CpuId::brand_string() {
89 return Utils::StrDup(s: brand_string_);
90}
91
92const char* CpuId::field(CpuInfoIndices idx) {
93 switch (idx) {
94 case kCpuInfoProcessor:
95 return id_string();
96 case kCpuInfoModel:
97 return brand_string();
98 case kCpuInfoHardware:
99 return brand_string();
100 case kCpuInfoFeatures: {
101 char buffer[100];
102 char* p = buffer;
103 const char* q = p + 100;
104 *p = '\0';
105 if (sse2()) {
106 p += snprintf(s: p, maxlen: q - p, format: "sse2 ");
107 }
108 if (sse41()) {
109 p += snprintf(s: p, maxlen: q - p, format: "sse4.1 ");
110 }
111 if (popcnt()) {
112 p += snprintf(s: p, maxlen: q - p, format: "popcnt ");
113 }
114 if (abm()) {
115 p += snprintf(s: p, maxlen: q - p, format: "abm ");
116 }
117 // Remove last space before returning string.
118 if (p != buffer) *(p - 1) = '\0';
119 return Utils::StrDup(s: buffer);
120 }
121 default: {
122 UNREACHABLE();
123 return nullptr;
124 }
125 }
126}
127
128#endif // defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
129} // namespace dart
130
131#endif // !defined(DART_HOST_OS_MACOS)
132

source code of flutter_engine/third_party/dart/runtime/vm/cpuid.cc