1 #include <stdio.h>
2 #include <stdint.h>
3 #include <stdlib.h>
4 #include <errno.h>
5
6 #include <cpuinfo.h>
7 #include <cpuinfo/internal-api.h>
8 #include <cpuinfo/log.h>
9
10 #include "windows-arm-init.h"
11
12 /* Efficiency class = 0 means little core, while 1 means big core for now */
13 #define MAX_WOA_VALID_EFFICIENCY_CLASSES 2
14 #define VENDOR_NAME_MAX CPUINFO_PACKAGE_NAME_MAX
15
16 struct cpuinfo_arm_isa cpuinfo_isa;
17
18 static void set_cpuinfo_isa_fields(void);
19 static bool get_system_info_from_registry(
20 struct woa_chip_info** chip_info,
21 enum cpuinfo_vendor* vendor);
22
23 struct vendor_info {
24 char vendor_name[VENDOR_NAME_MAX];
25 enum cpuinfo_vendor vendor;
26 };
27
28 /* Please add new vendor here! */
29 static struct vendor_info vendors[] = {
30 {
31 "Qualcomm",
32 cpuinfo_vendor_qualcomm
33 }
34 };
35
36 /* Please add new SoC/chip info here! */
37 static struct woa_chip_info woa_chips[] = {
38 /* Microsoft SQ1 Kryo 495 4 + 4 cores (3 GHz + 1.80 GHz) */
39 {
40 "Microsoft SQ1",
41 woa_chip_name_microsoft_sq_1,
42 {
43 {
44 cpuinfo_uarch_cortex_a55,
45 1800000000,
46 },
47 {
48 cpuinfo_uarch_cortex_a76,
49 3000000000,
50 }
51 }
52 },
53 /* Microsoft SQ2 Kryo 495 4 + 4 cores (3.15 GHz + 2.42 GHz) */
54 {
55 "Microsoft SQ2",
56 woa_chip_name_microsoft_sq_2,
57 {
58 {
59 cpuinfo_uarch_cortex_a55,
60 2420000000,
61 },
62 {
63 cpuinfo_uarch_cortex_a76,
64 3150000000
65 }
66 }
67 }
68 };
69
cpuinfo_arm_windows_init(PINIT_ONCE init_once,PVOID parameter,PVOID * context)70 BOOL CALLBACK cpuinfo_arm_windows_init(
71 PINIT_ONCE init_once, PVOID parameter, PVOID* context)
72 {
73 struct woa_chip_info *chip_info = NULL;
74 enum cpuinfo_vendor vendor = cpuinfo_vendor_unknown;
75 bool result = false;
76
77 set_cpuinfo_isa_fields();
78 result = get_system_info_from_registry(&chip_info, &vendor);
79 result &= cpu_info_init_by_logical_sys_info(chip_info, vendor);
80 cpuinfo_is_initialized = result;
81 return ((result == true) ? TRUE : FALSE);
82 }
83
get_core_uarch_for_efficiency(enum woa_chip_name chip,BYTE EfficiencyClass,enum cpuinfo_uarch * uarch,uint64_t * frequency)84 bool get_core_uarch_for_efficiency(
85 enum woa_chip_name chip, BYTE EfficiencyClass,
86 enum cpuinfo_uarch* uarch, uint64_t* frequency)
87 {
88 /* For currently supported WoA chips, the Efficiency class selects
89 * the pre-defined little and big core.
90 * Any further supported SoC's logic should be implemented here.
91 */
92 if (uarch && frequency && chip < woa_chip_name_last &&
93 EfficiencyClass < MAX_WOA_VALID_EFFICIENCY_CLASSES) {
94 *uarch = woa_chips[chip].uarchs[EfficiencyClass].uarch;
95 *frequency = woa_chips[chip].uarchs[EfficiencyClass].frequency;
96 return true;
97 }
98 return false;
99 }
100
101 /* Static helper functions */
102
read_registry(LPCTSTR subkey,LPCTSTR value,char ** textBuffer)103 static bool read_registry(
104 LPCTSTR subkey,
105 LPCTSTR value,
106 char** textBuffer)
107 {
108 DWORD keyType = 0;
109 DWORD dataSize = 0;
110 const DWORD flags = RRF_RT_REG_SZ; /* Only read strings (REG_SZ) */
111 LSTATUS result = 0;
112 HANDLE heap = GetProcessHeap();
113
114 result = RegGetValue(
115 HKEY_LOCAL_MACHINE,
116 subkey,
117 value,
118 flags,
119 &keyType,
120 NULL, /* Request buffer size */
121 &dataSize);
122 if (result != 0 || dataSize == 0) {
123 cpuinfo_log_error("Registry entry size read error");
124 return false;
125 }
126
127 if (*textBuffer) {
128 HeapFree(heap, 0, *textBuffer);
129 }
130 *textBuffer = HeapAlloc(heap, HEAP_ZERO_MEMORY, dataSize);
131 if (*textBuffer == NULL) {
132 cpuinfo_log_error("Registry textbuffer allocation error");
133 return false;
134 }
135
136 result = RegGetValue(
137 HKEY_LOCAL_MACHINE,
138 subkey,
139 value,
140 flags,
141 NULL,
142 *textBuffer, /* Write string in this destination buffer */
143 &dataSize);
144 if (result != 0) {
145 cpuinfo_log_error("Registry read error");
146 return false;
147 }
148 return true;
149 }
150
get_system_info_from_registry(struct woa_chip_info ** chip_info,enum cpuinfo_vendor * vendor)151 static bool get_system_info_from_registry(
152 struct woa_chip_info** chip_info,
153 enum cpuinfo_vendor* vendor)
154 {
155 bool result = false;
156 char* textBuffer = NULL;
157 LPCTSTR cpu0_subkey =
158 (LPCTSTR)"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0";
159 LPCTSTR chip_name_value = (LPCTSTR)"ProcessorNameString";
160 LPCTSTR vendor_name_value = (LPCTSTR)"VendorIdentifier";
161
162 *chip_info = NULL;
163 *vendor = cpuinfo_vendor_unknown;
164 HANDLE heap = GetProcessHeap();
165
166 /* 1. Read processor model name from registry and find in the hard-coded list. */
167 if (!read_registry(cpu0_subkey, chip_name_value, &textBuffer)) {
168 cpuinfo_log_error("Registry read error");
169 goto cleanup;
170 }
171 for (uint32_t i = 0; i < (uint32_t) woa_chip_name_last; i++) {
172 size_t compare_length = strnlen(woa_chips[i].chip_name_string, CPUINFO_PACKAGE_NAME_MAX);
173 int compare_result = strncmp(textBuffer, woa_chips[i].chip_name_string, compare_length);
174 if (compare_result == 0) {
175 *chip_info = woa_chips+i;
176 break;
177 }
178 }
179 if (*chip_info == NULL) {
180 cpuinfo_log_error("Unknown chip model name.\n Please add new Windows on Arm SoC/chip support!");
181 goto cleanup;
182 }
183 cpuinfo_log_debug("detected chip model name: %s", (**chip_info).chip_name_string);
184
185 /* 2. Read vendor/manufacturer name from registry. */
186 if (!read_registry(cpu0_subkey, vendor_name_value, &textBuffer)) {
187 cpuinfo_log_error("Registry read error");
188 goto cleanup;
189 }
190
191 for (uint32_t i = 0; i < (sizeof(vendors) / sizeof(struct vendor_info)); i++) {
192 if (strncmp(textBuffer, vendors[i].vendor_name,
193 strlen(vendors[i].vendor_name)) == 0) {
194 *vendor = vendors[i].vendor;
195 result = true;
196 break;
197 }
198 }
199 if (*vendor == cpuinfo_vendor_unknown) {
200 cpuinfo_log_error("Unexpected vendor: %s", textBuffer);
201 }
202
203 cleanup:
204 HeapFree(heap, 0, textBuffer);
205 textBuffer = NULL;
206 return result;
207 }
208
set_cpuinfo_isa_fields(void)209 static void set_cpuinfo_isa_fields(void)
210 {
211 bool armv8 = IsProcessorFeaturePresent(PF_ARM_V8_INSTRUCTIONS_AVAILABLE);
212 bool crypto = IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
213 bool load_store_atomic = IsProcessorFeaturePresent(PF_ARM_64BIT_LOADSTORE_ATOMIC);
214 bool float_multiply_accumulate = IsProcessorFeaturePresent(PF_ARM_FMAC_INSTRUCTIONS_AVAILABLE);
215 bool crc32 = IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE);
216 bool float_emulated = IsProcessorFeaturePresent(PF_FLOATING_POINT_EMULATED);
217
218 /* Read all Arm related Windows features for debug purposes, even if we can't
219 * pair Arm ISA feature to that now.
220 */
221 #if CPUINFO_LOG_DEBUG_PARSERS
222 bool divide = IsProcessorFeaturePresent(PF_ARM_DIVIDE_INSTRUCTION_AVAILABLE);
223 bool ext_cache = IsProcessorFeaturePresent(PF_ARM_EXTERNAL_CACHE_AVAILABLE);
224 bool vfp_registers = IsProcessorFeaturePresent(PF_ARM_VFP_32_REGISTERS_AVAILABLE);
225 bool arm_v81 = IsProcessorFeaturePresent(PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE);
226
227 cpuinfo_log_debug("divide present: %d", divide);
228 cpuinfo_log_debug("ext_cache present: %d", ext_cache);
229 cpuinfo_log_debug("vfp_registers present: %d", vfp_registers);
230 cpuinfo_log_debug("arm_v81 present: %d", arm_v81);
231 #endif
232
233 cpuinfo_log_debug("armv8 present: %d", armv8);
234 cpuinfo_log_debug("crypto present: %d", crypto);
235 cpuinfo_log_debug("load_store_atomic present: %d", load_store_atomic);
236 cpuinfo_log_debug("float_multiply_accumulate present: %d", float_multiply_accumulate);
237 cpuinfo_log_debug("crc32 present: %d", crc32);
238 cpuinfo_log_debug("float_emulated: %d", float_emulated);
239
240 #if CPUINFO_ARCH_ARM
241 cpuinfo_isa.armv8 = armv8;
242 #endif
243 #if CPUINFO_ARCH_ARM64
244 cpuinfo_isa.atomics = load_store_atomic;
245 #endif
246 cpuinfo_isa.crc32 = crc32;
247 /* Windows API reports all or nothing for cryptographic instructions. */
248 cpuinfo_isa.aes = crypto;
249 cpuinfo_isa.sha1 = crypto;
250 cpuinfo_isa.sha2 = crypto;
251 cpuinfo_isa.pmull = crypto;
252 cpuinfo_isa.fp16arith = !float_emulated && float_multiply_accumulate;
253 }
254