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