• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <errno.h>
2 #include <stdint.h>
3 #include <stdio.h>
4 #include <stdlib.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 struct cpuinfo_arm_isa cpuinfo_isa;
13 
14 static void set_cpuinfo_isa_fields(void);
15 static struct woa_chip_info* get_system_info_from_registry(void);
16 
17 static struct woa_chip_info woa_chip_unknown = {
18 	L"Unknown",
19 	woa_chip_name_unknown,
20 	{{cpuinfo_vendor_unknown, cpuinfo_uarch_unknown, 0}}};
21 
22 /* Please add new SoC/chip info here! */
23 static struct woa_chip_info woa_chips[woa_chip_name_last] = {
24 	/* Microsoft SQ1 Kryo 495 4 + 4 cores (3 GHz + 1.80 GHz) */
25 	[woa_chip_name_microsoft_sq_1] =
26 		{L"Microsoft SQ1",
27 		 woa_chip_name_microsoft_sq_1,
28 		 {{
29 			  cpuinfo_vendor_arm,
30 			  cpuinfo_uarch_cortex_a55,
31 			  1800000000,
32 		  },
33 		  {
34 			  cpuinfo_vendor_arm,
35 			  cpuinfo_uarch_cortex_a76,
36 			  3000000000,
37 		  }}},
38 	/* Microsoft SQ2 Kryo 495 4 + 4 cores (3.15 GHz + 2.42 GHz) */
39 	[woa_chip_name_microsoft_sq_2] =
40 		{L"Microsoft SQ2",
41 		 woa_chip_name_microsoft_sq_2,
42 		 {{
43 			  cpuinfo_vendor_arm,
44 			  cpuinfo_uarch_cortex_a55,
45 			  2420000000,
46 		  },
47 		  {cpuinfo_vendor_arm, cpuinfo_uarch_cortex_a76, 3150000000}}},
48 	/* Snapdragon (TM) 8cx Gen 3 @ 3.0 GHz */
49 	[woa_chip_name_microsoft_sq_3] =
50 		{L"Snapdragon (TM) 8cx Gen 3",
51 		 woa_chip_name_microsoft_sq_3,
52 		 {{
53 			  cpuinfo_vendor_arm,
54 			  cpuinfo_uarch_cortex_a78,
55 			  2420000000,
56 		  },
57 		  {cpuinfo_vendor_arm, cpuinfo_uarch_cortex_x1, 3000000000}}},
58 	/* Microsoft Windows Dev Kit 2023 */
59 	[woa_chip_name_microsoft_sq_3_devkit] =
60 		{L"Snapdragon Compute Platform",
61 		 woa_chip_name_microsoft_sq_3_devkit,
62 		 {{
63 			  cpuinfo_vendor_arm,
64 			  cpuinfo_uarch_cortex_a78,
65 			  2420000000,
66 		  },
67 		  {cpuinfo_vendor_arm, cpuinfo_uarch_cortex_x1, 3000000000}}},
68 	/* Ampere Altra */
69 	[woa_chip_name_ampere_altra] = {
70 		L"Ampere(R) Altra(R) Processor",
71 		woa_chip_name_ampere_altra,
72 		{{cpuinfo_vendor_arm, cpuinfo_uarch_neoverse_n1, 3000000000}}}};
73 
cpuinfo_arm_windows_init(PINIT_ONCE init_once,PVOID parameter,PVOID * context)74 BOOL CALLBACK cpuinfo_arm_windows_init(PINIT_ONCE init_once, PVOID parameter, PVOID* context) {
75 	struct woa_chip_info* chip_info = NULL;
76 	enum cpuinfo_vendor vendor = cpuinfo_vendor_unknown;
77 
78 	set_cpuinfo_isa_fields();
79 
80 	chip_info = get_system_info_from_registry();
81 	if (chip_info == NULL) {
82 		chip_info = &woa_chip_unknown;
83 	}
84 
85 	cpuinfo_is_initialized = cpu_info_init_by_logical_sys_info(chip_info, chip_info->uarchs[0].vendor);
86 
87 	return true;
88 }
89 
get_core_uarch_for_efficiency(enum woa_chip_name chip,BYTE EfficiencyClass,enum cpuinfo_uarch * uarch,uint64_t * frequency)90 bool get_core_uarch_for_efficiency(
91 	enum woa_chip_name chip,
92 	BYTE EfficiencyClass,
93 	enum cpuinfo_uarch* uarch,
94 	uint64_t* frequency) {
95 	/* For currently supported WoA chips, the Efficiency class selects
96 	 * the pre-defined little and big core.
97 	 * Any further supported SoC's logic should be implemented here.
98 	 */
99 	if (uarch && frequency && chip < woa_chip_name_last && EfficiencyClass < MAX_WOA_VALID_EFFICIENCY_CLASSES) {
100 		*uarch = woa_chips[chip].uarchs[EfficiencyClass].uarch;
101 		*frequency = woa_chips[chip].uarchs[EfficiencyClass].frequency;
102 		return true;
103 	}
104 	return false;
105 }
106 
107 /* Static helper functions */
108 
read_registry(LPCWSTR subkey,LPCWSTR value)109 static wchar_t* read_registry(LPCWSTR subkey, LPCWSTR value) {
110 	DWORD key_type = 0;
111 	DWORD data_size = 0;
112 	const DWORD flags = RRF_RT_REG_SZ; /* Only read strings (REG_SZ) */
113 	wchar_t* text_buffer = NULL;
114 	LSTATUS result = 0;
115 	HANDLE heap = GetProcessHeap();
116 
117 	result = RegGetValueW(
118 		HKEY_LOCAL_MACHINE,
119 		subkey,
120 		value,
121 		flags,
122 		&key_type,
123 		NULL, /* Request buffer size */
124 		&data_size);
125 	if (result != 0 || data_size == 0) {
126 		cpuinfo_log_error("Registry entry size read error");
127 		return NULL;
128 	}
129 
130 	text_buffer = HeapAlloc(heap, HEAP_ZERO_MEMORY, data_size);
131 	if (text_buffer == NULL) {
132 		cpuinfo_log_error("Registry textbuffer allocation error");
133 		return NULL;
134 	}
135 
136 	result = RegGetValueW(
137 		HKEY_LOCAL_MACHINE,
138 		subkey,
139 		value,
140 		flags,
141 		NULL,
142 		text_buffer, /* Write string in this destination buffer */
143 		&data_size);
144 	if (result != 0) {
145 		cpuinfo_log_error("Registry read error");
146 		HeapFree(heap, 0, text_buffer);
147 		return NULL;
148 	}
149 	return text_buffer;
150 }
151 
get_system_info_from_registry(void)152 static struct woa_chip_info* get_system_info_from_registry(void) {
153 	wchar_t* text_buffer = NULL;
154 	LPCWSTR cpu0_subkey = L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0";
155 	LPCWSTR chip_name_value = L"ProcessorNameString";
156 	struct woa_chip_info* chip_info = NULL;
157 
158 	HANDLE heap = GetProcessHeap();
159 
160 	/* Read processor model name from registry and find in the hard-coded
161 	 * list. */
162 	text_buffer = read_registry(cpu0_subkey, chip_name_value);
163 	if (text_buffer == NULL) {
164 		cpuinfo_log_error("Registry read error");
165 		return NULL;
166 	}
167 	for (uint32_t i = 0; i < (uint32_t)woa_chip_name_last; i++) {
168 		size_t compare_length = wcsnlen(woa_chips[i].chip_name_string, CPUINFO_PACKAGE_NAME_MAX);
169 		int compare_result = wcsncmp(text_buffer, woa_chips[i].chip_name_string, compare_length);
170 		if (compare_result == 0) {
171 			chip_info = woa_chips + i;
172 			break;
173 		}
174 	}
175 	if (chip_info == NULL) {
176 		/* No match was found, so print a warning and assign the unknown
177 		 * case. */
178 		cpuinfo_log_error(
179 			"Unknown chip model name '%ls'.\nPlease add new Windows on Arm SoC/chip support to arm/windows/init.c!",
180 			text_buffer);
181 	} else {
182 		cpuinfo_log_debug("detected chip model name: %s", chip_info->chip_name_string);
183 	}
184 
185 	HeapFree(heap, 0, text_buffer);
186 	return chip_info;
187 }
188 
set_cpuinfo_isa_fields(void)189 static void set_cpuinfo_isa_fields(void) {
190 	cpuinfo_isa.atomics = IsProcessorFeaturePresent(PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE) != 0;
191 
192 	const bool dotprod = IsProcessorFeaturePresent(PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE) != 0;
193 	cpuinfo_isa.dot = dotprod;
194 
195 	SYSTEM_INFO system_info;
196 	GetSystemInfo(&system_info);
197 	switch (system_info.wProcessorLevel) {
198 		case 0x803: // Kryo 385 Silver (Snapdragon 850)
199 			cpuinfo_isa.fp16arith = dotprod;
200 			cpuinfo_isa.rdm = dotprod;
201 			break;
202 		default:
203 			// Assume that Dot Product support implies FP16
204 			// arithmetics and RDM support. ARM manuals don't
205 			// guarantee that, but it holds in practice.
206 			cpuinfo_isa.fp16arith = dotprod;
207 			cpuinfo_isa.rdm = dotprod;
208 			break;
209 	}
210 
211 	/* Windows API reports all or nothing for cryptographic instructions. */
212 	const bool crypto = IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) != 0;
213 	cpuinfo_isa.aes = crypto;
214 	cpuinfo_isa.sha1 = crypto;
215 	cpuinfo_isa.sha2 = crypto;
216 	cpuinfo_isa.pmull = crypto;
217 
218 	cpuinfo_isa.crc32 = IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE) != 0;
219 }
220