xref: /aosp_15_r20/external/cpuinfo/src/arm/windows/init-by-logical-sys-info.c (revision 2b54f0db79fd8303838913b20ff3780cddaa909f)
1 #include <stdio.h>
2 #include <stdint.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <malloc.h>
6 #include <errno.h>
7 #include <sys/types.h>
8 
9 #include <cpuinfo.h>
10 #include <cpuinfo/internal-api.h>
11 #include <cpuinfo/log.h>
12 
13 #include "windows-arm-init.h"
14 
15 #define MAX_NR_OF_CACHES	(cpuinfo_cache_level_max - 1)
16 
17 /* Call chain:
18  * cpu_info_init_by_logical_sys_info
19  * 		read_packages_for_processors
20  * 		read_cores_for_processors
21  * 		read_caches_for_processors
22  * 			read_all_logical_processor_info_of_relation
23  * 				parse_relation_processor_info
24  * 					store_package_info_per_processor
25  * 					store_core_info_per_processor
26  * 				parse_relation_cache_info
27  * 					store_cache_info_per_processor
28  */
29 
30 static uint32_t count_logical_processors(
31 	const uint32_t max_group_count,
32 	uint32_t* global_proc_index_per_group);
33 
34 static uint32_t read_packages_for_processors(
35 	struct cpuinfo_processor* processors,
36 	const uint32_t number_of_processors,
37 	const uint32_t* global_proc_index_per_group,
38 	const struct woa_chip_info *chip_info);
39 
40 static uint32_t read_cores_for_processors(
41 	struct cpuinfo_processor* processors,
42 	const uint32_t number_of_processors,
43 	const uint32_t* global_proc_index_per_group,
44 	struct cpuinfo_core* cores,
45 	const struct woa_chip_info *chip_info);
46 
47 static uint32_t read_caches_for_processors(
48 	struct cpuinfo_processor *processors,
49 	const uint32_t number_of_processors,
50 	struct cpuinfo_cache *caches,
51 	uint32_t* numbers_of_caches,
52 	const uint32_t* global_proc_index_per_group,
53 	const struct woa_chip_info *chip_info);
54 
55 static uint32_t read_all_logical_processor_info_of_relation(
56 	LOGICAL_PROCESSOR_RELATIONSHIP info_type,
57 	struct cpuinfo_processor* processors,
58 	const uint32_t number_of_processors,
59 	struct cpuinfo_cache* caches,
60 	uint32_t* numbers_of_caches,
61 	struct cpuinfo_core* cores,
62 	const uint32_t* global_proc_index_per_group,
63 	const struct woa_chip_info *chip_info);
64 
65 static bool parse_relation_processor_info(
66 	struct cpuinfo_processor* processors,
67 	uint32_t nr_of_processors,
68 	const uint32_t* global_proc_index_per_group,
69 	PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX info,
70 	const uint32_t info_id,
71 	struct cpuinfo_core* cores,
72 	const struct woa_chip_info *chip_info);
73 
74 static bool parse_relation_cache_info(
75 	struct cpuinfo_processor* processors,
76 	struct cpuinfo_cache* caches,
77 	uint32_t* numbers_of_caches,
78 	const uint32_t* global_proc_index_per_group,
79 	PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX info);
80 
81 static void store_package_info_per_processor(
82 	struct cpuinfo_processor* processors,
83 	const uint32_t processor_global_index,
84 	const uint32_t package_id,
85 	const uint32_t group_id,
86 	const uint32_t processor_id_in_group);
87 
88 static void store_core_info_per_processor(
89 	struct cpuinfo_processor* processors,
90 	const uint32_t processor_global_index,
91 	const uint32_t core_id,
92 	PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX core_info,
93 	struct cpuinfo_core* cores,
94 	const struct woa_chip_info *chip_info);
95 
96 static void store_cache_info_per_processor(
97 	struct cpuinfo_processor* processors,
98 	const uint32_t processor_global_index,
99 	PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX info,
100 	struct cpuinfo_cache* current_cache);
101 
102 static bool connect_packages_cores_clusters_by_processors(
103 	struct cpuinfo_processor* processors,
104 	const uint32_t nr_of_processors,
105 	struct cpuinfo_package* packages,
106 	const uint32_t nr_of_packages,
107 	struct cpuinfo_cluster* clusters,
108 	struct cpuinfo_core* cores,
109 	const uint32_t nr_of_cores,
110 	const struct woa_chip_info* chip_info,
111 	enum cpuinfo_vendor vendor);
112 
113 static inline uint32_t low_index_from_kaffinity(KAFFINITY kaffinity);
114 
115 
cpu_info_init_by_logical_sys_info(const struct woa_chip_info * chip_info,const enum cpuinfo_vendor vendor)116 bool cpu_info_init_by_logical_sys_info(
117 	const struct woa_chip_info *chip_info,
118 	const enum cpuinfo_vendor vendor)
119 {
120 	struct cpuinfo_processor* processors = NULL;
121 	struct cpuinfo_package* packages = NULL;
122 	struct cpuinfo_cluster* clusters = NULL;
123 	struct cpuinfo_core* cores = NULL;
124 	struct cpuinfo_cache* caches = NULL;
125 	struct cpuinfo_uarch_info* uarchs = NULL;
126 
127 	uint32_t nr_of_packages = 0;
128 	uint32_t nr_of_cores = 0;
129 	uint32_t nr_of_all_caches = 0;
130 	uint32_t numbers_of_caches[MAX_NR_OF_CACHES] = {0};
131 
132 	uint32_t nr_of_uarchs = 0;
133 	bool result = false;
134 
135 	HANDLE heap = GetProcessHeap();
136 
137 	/* 1. Count available logical processor groups and processors */
138 	const uint32_t max_group_count = (uint32_t) GetMaximumProcessorGroupCount();
139 	cpuinfo_log_debug("detected %"PRIu32" processor group(s)", max_group_count);
140 	/* We need to store the absolute processor ID offsets for every groups, because
141 	 *  1. We can't assume every processor groups include the same number of
142 	 *     logical processors.
143 	 *  2. Every processor groups know its group number and processor IDs within
144 	 *     the group, but not the global processor IDs.
145 	 *  3. We need to list every logical processors by global IDs.
146 	*/
147 	uint32_t* global_proc_index_per_group =
148 		(uint32_t*) HeapAlloc(heap, 0, max_group_count * sizeof(uint32_t));
149 	if (global_proc_index_per_group == NULL) {
150 		cpuinfo_log_error(
151 			"failed to allocate %zu bytes for descriptions of %"PRIu32" processor groups",
152 			max_group_count * sizeof(struct cpuinfo_processor), max_group_count);
153 		goto clean_up;
154 	}
155 
156 	uint32_t nr_of_processors =
157 		count_logical_processors(max_group_count, global_proc_index_per_group);
158 	processors = HeapAlloc(heap, HEAP_ZERO_MEMORY, nr_of_processors * sizeof(struct cpuinfo_processor));
159 	if (processors == NULL) {
160 		cpuinfo_log_error(
161 			"failed to allocate %zu bytes for descriptions of %"PRIu32" logical processors",
162 			nr_of_processors * sizeof(struct cpuinfo_processor), nr_of_processors);
163 		goto clean_up;
164 	}
165 
166 	/* 2. Read topology information via MSDN API: packages, cores and caches*/
167 	nr_of_packages = read_packages_for_processors(
168 						processors, nr_of_processors,
169 						global_proc_index_per_group,
170 						chip_info);
171 	if (!nr_of_packages) {
172 		cpuinfo_log_error("error in reading package information");
173 		goto clean_up;
174 	}
175 	cpuinfo_log_debug("detected %"PRIu32" processor package(s)", nr_of_packages);
176 
177 	/* We need the EfficiencyClass to parse uarch from the core information,
178 	 * but we need to iterate first to count cores and allocate memory then
179 	 * we will iterate again to read and store data to cpuinfo_core structures.
180 	 */
181 	nr_of_cores = read_cores_for_processors(
182 					processors, nr_of_processors,
183 					global_proc_index_per_group, NULL,
184 					chip_info);
185 	if (!nr_of_cores) {
186 		cpuinfo_log_error("error in reading core information");
187 		goto clean_up;
188 	}
189 	cpuinfo_log_debug("detected %"PRIu32" processor core(s)", nr_of_cores);
190 
191 	/* There is no API to read number of caches, so we need to iterate twice on caches:
192 		1. Count all type of caches -> allocate memory
193 		2. Read out cache data and store to allocated memory
194 	 */
195 	nr_of_all_caches = read_caches_for_processors(
196 						processors, nr_of_processors,
197 						caches, numbers_of_caches,
198 						global_proc_index_per_group, chip_info);
199 	if (!nr_of_all_caches) {
200 		cpuinfo_log_error("error in reading cache information");
201 		goto clean_up;
202 	}
203 	cpuinfo_log_debug("detected %"PRIu32" processor cache(s)", nr_of_all_caches);
204 
205 	/* 3. Allocate memory for package, cluster, core and cache structures */
206 	packages = HeapAlloc(heap, HEAP_ZERO_MEMORY, nr_of_packages * sizeof(struct cpuinfo_package));
207 	if (packages == NULL) {
208 		cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" physical packages",
209 			nr_of_packages * sizeof(struct cpuinfo_package), nr_of_packages);
210 		goto clean_up;
211 	}
212 
213 	/* We don't have cluster information so we explicitly set clusters to equal to cores. */
214 	clusters = HeapAlloc(heap, HEAP_ZERO_MEMORY, nr_of_cores * sizeof(struct cpuinfo_cluster));
215 	if (clusters == NULL) {
216 		cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" core clusters",
217 			nr_of_cores * sizeof(struct cpuinfo_cluster), nr_of_cores);
218 		goto clean_up;
219 	}
220 
221 	cores = HeapAlloc(heap, HEAP_ZERO_MEMORY, nr_of_cores * sizeof(struct cpuinfo_core));
222 	if (cores == NULL) {
223 		cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" cores",
224 			nr_of_cores * sizeof(struct cpuinfo_core), nr_of_cores);
225 		goto clean_up;
226 	}
227 
228 	/* We allocate one contiguous cache array for all caches, then use offsets per cache type. */
229 	caches = HeapAlloc(heap, HEAP_ZERO_MEMORY, nr_of_all_caches * sizeof(struct cpuinfo_cache));
230 	if (caches == NULL) {
231 		cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" caches",
232 			nr_of_all_caches * sizeof(struct cpuinfo_cache), nr_of_all_caches);
233 		goto clean_up;
234 	}
235 
236 	/* 4.Read missing topology information that can't be saved without counted
237 	 *   allocate structures in the first round.
238 	 */
239 	nr_of_all_caches = read_caches_for_processors(
240 						processors, nr_of_processors,
241 						caches, numbers_of_caches, global_proc_index_per_group, chip_info);
242 	if (!nr_of_all_caches) {
243 		cpuinfo_log_error("error in reading cache information");
244 		goto clean_up;
245 	}
246 
247 	nr_of_cores = read_cores_for_processors(
248 		processors, nr_of_processors,
249 		global_proc_index_per_group, cores,
250 		chip_info);
251 	if (!nr_of_cores) {
252 		cpuinfo_log_error("error in reading core information");
253 		goto clean_up;
254 	}
255 
256 	/* 5. Now that we read out everything from the system we can, fill the package, cluster
257 	 *    and core structures respectively.
258 	 */
259 	result = connect_packages_cores_clusters_by_processors(
260 				processors, nr_of_processors,
261 				packages, nr_of_packages,
262 				clusters,
263 				cores, nr_of_cores,
264 				chip_info,
265 				vendor);
266 	if(!result) {
267 		cpuinfo_log_error("error in connecting information");
268 		goto clean_up;
269 	}
270 
271 	/* 6. Count and store uarchs of cores, assuming same uarchs are neighbors */
272 	enum cpuinfo_uarch prev_uarch = cpuinfo_uarch_unknown;
273 	for (uint32_t i = 0; i < nr_of_cores; i++) {
274 		if (prev_uarch != cores[i].uarch) {
275 			nr_of_uarchs++;
276 			prev_uarch = cores[i].uarch;
277 		}
278 	}
279 	uarchs = HeapAlloc(heap, HEAP_ZERO_MEMORY, nr_of_uarchs * sizeof(struct cpuinfo_uarch_info));
280 	if (uarchs == NULL) {
281 		cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" uarchs",
282 			nr_of_uarchs * sizeof(struct cpuinfo_uarch_info), nr_of_uarchs);
283 		goto clean_up;
284 	}
285 	prev_uarch = cpuinfo_uarch_unknown;
286 	for (uint32_t i = 0, uarch_counter = 0; i < nr_of_cores; i++) {
287 		if (prev_uarch != cores[i].uarch) {
288 			prev_uarch = cores[i].uarch;
289 			uarchs[uarch_counter].uarch = cores[i].uarch;
290 			uarchs[uarch_counter].core_count = 1;
291 			uarchs[uarch_counter].processor_count = cores[i].processor_count;
292 			uarch_counter++;
293 		} else if (prev_uarch != cpuinfo_uarch_unknown) {
294 			uarchs[uarch_counter].core_count++;
295 			uarchs[uarch_counter].processor_count += cores[i].processor_count;
296 		}
297 	}
298 
299 	/* 7. Commit changes */
300 	cpuinfo_processors = processors;
301 	cpuinfo_packages = packages;
302 	cpuinfo_clusters = clusters;
303 	cpuinfo_cores = cores;
304 	cpuinfo_uarchs = uarchs;
305 
306 	cpuinfo_processors_count = nr_of_processors;
307 	cpuinfo_packages_count = nr_of_packages;
308 	cpuinfo_clusters_count = nr_of_cores;
309 	cpuinfo_cores_count = nr_of_cores;
310 	cpuinfo_uarchs_count = nr_of_uarchs;
311 
312 	for (uint32_t i = 0; i < MAX_NR_OF_CACHES; i++) {
313 		cpuinfo_cache_count[i] = numbers_of_caches[i];
314 	}
315 	cpuinfo_cache[cpuinfo_cache_level_1i] = caches;
316 	cpuinfo_cache[cpuinfo_cache_level_1d] = cpuinfo_cache[cpuinfo_cache_level_1i] + cpuinfo_cache_count[cpuinfo_cache_level_1i];
317 	cpuinfo_cache[cpuinfo_cache_level_2]  = cpuinfo_cache[cpuinfo_cache_level_1d] + cpuinfo_cache_count[cpuinfo_cache_level_1d];
318 	cpuinfo_cache[cpuinfo_cache_level_3]  = cpuinfo_cache[cpuinfo_cache_level_2]  + cpuinfo_cache_count[cpuinfo_cache_level_2];
319 	cpuinfo_cache[cpuinfo_cache_level_4]  = cpuinfo_cache[cpuinfo_cache_level_3]  + cpuinfo_cache_count[cpuinfo_cache_level_3];
320 	cpuinfo_max_cache_size = cpuinfo_compute_max_cache_size(&processors[0]);
321 
322 	result = true;
323 	MemoryBarrier();
324 
325 	processors = NULL;
326 	packages = NULL;
327 	clusters = NULL;
328 	cores = NULL;
329 	caches = NULL;
330 	uarchs = NULL;
331 
332 clean_up:
333 	/* The propagated pointers, shouldn't be freed, only in case of error
334 	 * and unfinished init.
335 	 */
336 	if (processors != NULL) {
337 		HeapFree(heap, 0, processors);
338 	}
339 	if (packages != NULL) {
340 		HeapFree(heap, 0, packages);
341 	}
342 	if (clusters != NULL) {
343 		HeapFree(heap, 0, clusters);
344 	}
345 	if (cores != NULL) {
346 		HeapFree(heap, 0, cores);
347 	}
348 	if (caches != NULL) {
349 		HeapFree(heap, 0, caches);
350 	}
351 	if (uarchs != NULL) {
352 		HeapFree(heap, 0, uarchs);
353 	}
354 
355 	/* Free the locally used temporary pointers */
356 	HeapFree(heap, 0, global_proc_index_per_group);
357 	global_proc_index_per_group = NULL;
358 	return result;
359 }
360 
count_logical_processors(const uint32_t max_group_count,uint32_t * global_proc_index_per_group)361 static uint32_t count_logical_processors(
362 	const uint32_t max_group_count,
363 	uint32_t* global_proc_index_per_group)
364 {
365 	uint32_t nr_of_processors = 0;
366 
367 	for (uint32_t i = 0; i < max_group_count; i++) {
368 		uint32_t nr_of_processors_per_group = GetMaximumProcessorCount((WORD) i);
369 		cpuinfo_log_debug("detected %"PRIu32" processor(s) in group %"PRIu32"",
370 			nr_of_processors_per_group, i);
371 		global_proc_index_per_group[i] = nr_of_processors;
372 		nr_of_processors += nr_of_processors_per_group;
373 	}
374 	return nr_of_processors;
375 }
376 
read_packages_for_processors(struct cpuinfo_processor * processors,const uint32_t number_of_processors,const uint32_t * global_proc_index_per_group,const struct woa_chip_info * chip_info)377 static uint32_t read_packages_for_processors(
378 	struct cpuinfo_processor* processors,
379 	const uint32_t number_of_processors,
380 	const uint32_t* global_proc_index_per_group,
381 	const struct woa_chip_info *chip_info)
382 {
383 	return read_all_logical_processor_info_of_relation(
384 		RelationProcessorPackage,
385 		processors,
386 		number_of_processors,
387 		NULL,
388 		NULL,
389 		NULL,
390 		global_proc_index_per_group,
391 		chip_info);
392 }
393 
read_cores_for_processors(struct cpuinfo_processor * processors,const uint32_t number_of_processors,const uint32_t * global_proc_index_per_group,struct cpuinfo_core * cores,const struct woa_chip_info * chip_info)394 uint32_t read_cores_for_processors(
395 	struct cpuinfo_processor* processors,
396 	const uint32_t number_of_processors,
397 	const uint32_t* global_proc_index_per_group,
398 	struct cpuinfo_core* cores,
399 	const struct woa_chip_info *chip_info)
400 {
401 	return read_all_logical_processor_info_of_relation(
402 		RelationProcessorCore,
403 		processors,
404 		number_of_processors,
405 		NULL,
406 		NULL,
407 		cores,
408 		global_proc_index_per_group,
409 		chip_info);
410 }
411 
read_caches_for_processors(struct cpuinfo_processor * processors,const uint32_t number_of_processors,struct cpuinfo_cache * caches,uint32_t * numbers_of_caches,const uint32_t * global_proc_index_per_group,const struct woa_chip_info * chip_info)412 static uint32_t read_caches_for_processors(
413 	struct cpuinfo_processor* processors,
414 	const uint32_t number_of_processors,
415 	struct cpuinfo_cache* caches,
416 	uint32_t* numbers_of_caches,
417 	const uint32_t* global_proc_index_per_group,
418 	const struct woa_chip_info *chip_info)
419 {
420 	/* Reset processor start indexes */
421 	if (caches) {
422 		uint32_t cache_offset = 0;
423 		for (uint32_t i = 0; i < MAX_NR_OF_CACHES; i++) {
424 			for (uint32_t j = 0; j < numbers_of_caches[i]; j++) {
425 				caches[cache_offset + j].processor_start = UINT32_MAX;
426 			}
427 			cache_offset += numbers_of_caches[i];
428 		}
429 	}
430 
431 	return read_all_logical_processor_info_of_relation(
432 		RelationCache,
433 		processors,
434 		number_of_processors,
435 		caches,
436 		numbers_of_caches,
437 		NULL,
438 		global_proc_index_per_group,
439 		chip_info);
440 }
441 
read_all_logical_processor_info_of_relation(LOGICAL_PROCESSOR_RELATIONSHIP info_type,struct cpuinfo_processor * processors,const uint32_t number_of_processors,struct cpuinfo_cache * caches,uint32_t * numbers_of_caches,struct cpuinfo_core * cores,const uint32_t * global_proc_index_per_group,const struct woa_chip_info * chip_info)442 static uint32_t read_all_logical_processor_info_of_relation(
443 	LOGICAL_PROCESSOR_RELATIONSHIP info_type,
444 	struct cpuinfo_processor* processors,
445 	const uint32_t number_of_processors,
446 	struct cpuinfo_cache* caches,
447 	uint32_t* numbers_of_caches,
448 	struct cpuinfo_core* cores,
449 	const uint32_t* global_proc_index_per_group,
450 	const struct woa_chip_info* chip_info)
451 {
452 	PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX infos = NULL;
453 	uint32_t nr_of_structs = 0;
454 	DWORD info_size = 0;
455 	bool result = false;
456 	HANDLE heap = GetProcessHeap();
457 
458 	/* 1. Query the size of the information structure first */
459 	if (GetLogicalProcessorInformationEx(info_type, NULL, &info_size) == FALSE) {
460 		const DWORD last_error = GetLastError();
461 		if (last_error != ERROR_INSUFFICIENT_BUFFER) {
462 			cpuinfo_log_error(
463 				"failed to query size of processor %"PRIu32" information information: error %"PRIu32"",
464 				(uint32_t)info_type, (uint32_t) last_error);
465 			goto clean_up;
466 		}
467 	}
468 	/* 2. Allocate memory for the information structure */
469 	infos = HeapAlloc(heap, 0, info_size);
470 	if (infos == NULL) {
471 		cpuinfo_log_error("failed to allocate %"PRIu32" bytes for logical processor information",
472 			(uint32_t) info_size);
473 		goto clean_up;
474 	}
475 	/* 3. Read the information structure */
476 	if (GetLogicalProcessorInformationEx(info_type, infos, &info_size) == FALSE) {
477 		cpuinfo_log_error("failed to query processor %"PRIu32" information: error %"PRIu32"",
478 			(uint32_t)info_type, (uint32_t) GetLastError());
479 		goto clean_up;
480 	}
481 
482 	/* 4. Parse the structure and store relevant data */
483 	PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX info_end =
484 		(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX) ((uintptr_t) infos + info_size);
485 	for (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX info = infos;
486 		info < info_end;
487 		info = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX) ((uintptr_t) info + info->Size))
488 	{
489 		if (info->Relationship != info_type) {
490 			cpuinfo_log_warning(
491 				"unexpected processor info type (%"PRIu32") for processor information",
492 				(uint32_t) info->Relationship);
493 			continue;
494 		}
495 
496 		const uint32_t info_id = nr_of_structs++;
497 
498 		switch(info_type) {
499 			case RelationProcessorPackage:
500 				result = parse_relation_processor_info(
501 							processors,
502 							number_of_processors,
503 							global_proc_index_per_group,
504 							info,
505 							info_id,
506 							cores,
507 							chip_info);
508 			break;
509 			case RelationProcessorCore:
510 				result = parse_relation_processor_info(
511 							processors,
512 							number_of_processors,
513 							global_proc_index_per_group,
514 							info,
515 							info_id,
516 							cores,
517 							chip_info);
518 			break;
519 			case RelationCache:
520 				result = parse_relation_cache_info(
521 							processors,
522 							caches,
523 							numbers_of_caches,
524 							global_proc_index_per_group,
525 							info);
526 			break;
527 			default:
528 				cpuinfo_log_error(
529 					"unexpected processor info type (%"PRIu32") for processor information",
530 					(uint32_t) info->Relationship);
531 				result = false;
532 			break;
533 		}
534 		if (!result) {
535 			nr_of_structs = 0;
536 			goto clean_up;
537 		}
538 	}
539 clean_up:
540 	/* 5. Release dynamically allocated info structure. */
541 	HeapFree(heap, 0, infos);
542 	infos = NULL;
543 	return nr_of_structs;
544 }
545 
parse_relation_processor_info(struct cpuinfo_processor * processors,uint32_t nr_of_processors,const uint32_t * global_proc_index_per_group,PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX info,const uint32_t info_id,struct cpuinfo_core * cores,const struct woa_chip_info * chip_info)546 static bool parse_relation_processor_info(
547 	struct cpuinfo_processor* processors,
548 	uint32_t nr_of_processors,
549 	const uint32_t* global_proc_index_per_group,
550 	PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX info,
551 	const uint32_t info_id,
552 	struct cpuinfo_core* cores,
553 	const struct woa_chip_info *chip_info)
554 {
555 	for (uint32_t i = 0; i < info->Processor.GroupCount; i++) {
556 		const uint32_t group_id = info->Processor.GroupMask[i].Group;
557 		/* Bitmask representing processors in this group belonging to this package */
558 		KAFFINITY group_processors_mask = info->Processor.GroupMask[i].Mask;
559 		while (group_processors_mask != 0) {
560 			const uint32_t processor_id_in_group =
561 				low_index_from_kaffinity(group_processors_mask);
562 			const uint32_t processor_global_index =
563 				global_proc_index_per_group[group_id] + processor_id_in_group;
564 
565 			if(processor_global_index >= nr_of_processors) {
566 				cpuinfo_log_error("unexpected processor index %"PRIu32"",
567 					processor_global_index);
568 				return false;
569 			}
570 
571 			switch(info->Relationship) {
572 				case RelationProcessorPackage:
573 					store_package_info_per_processor(
574 						processors, processor_global_index, info_id,
575 						group_id, processor_id_in_group);
576 				break;
577 				case RelationProcessorCore:
578 					store_core_info_per_processor(
579 						processors, processor_global_index,
580 						info_id, info,
581 						cores, chip_info);
582 				break;
583 				default:
584 					cpuinfo_log_error(
585 						"unexpected processor info type (%"PRIu32") for processor information",
586 						(uint32_t) info->Relationship);
587 				break;
588 			}
589 			/* Clear the bits in affinity mask, lower the least set bit. */
590 			group_processors_mask &= (group_processors_mask - 1);
591 		}
592 	}
593 	return true;
594 }
595 
parse_relation_cache_info(struct cpuinfo_processor * processors,struct cpuinfo_cache * caches,uint32_t * numbers_of_caches,const uint32_t * global_proc_index_per_group,PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX info)596 static bool parse_relation_cache_info(
597 	struct cpuinfo_processor* processors,
598 	struct cpuinfo_cache* caches,
599 	uint32_t* numbers_of_caches,
600 	const uint32_t* global_proc_index_per_group,
601 	PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX info)
602 {
603 	static uint32_t l1i_counter = 0;
604 	static uint32_t l1d_counter = 0;
605 	static uint32_t l2_counter = 0;
606 	static uint32_t l3_counter = 0;
607 
608 	/* Count cache types for allocation at first. */
609 	if (caches == NULL) {
610 		switch(info->Cache.Level) {
611 			case 1:
612 				switch (info->Cache.Type) {
613 					case CacheInstruction:
614 						numbers_of_caches[cpuinfo_cache_level_1i]++;
615 					break;
616 					case CacheData:
617 						numbers_of_caches[cpuinfo_cache_level_1d]++;
618 					break;
619 					case CacheUnified:
620 					break;
621 					case CacheTrace:
622 					break;
623 					default:
624 					break;
625 				}
626 			break;
627 			case 2:
628 				numbers_of_caches[cpuinfo_cache_level_2]++;
629 			break;
630 			case 3:
631 				numbers_of_caches[cpuinfo_cache_level_3]++;
632 			break;
633 		}
634 		return true;
635 	}
636 	struct cpuinfo_cache* l1i_base = caches;
637 	struct cpuinfo_cache* l1d_base = l1i_base + numbers_of_caches[cpuinfo_cache_level_1i];
638 	struct cpuinfo_cache* l2_base  = l1d_base + numbers_of_caches[cpuinfo_cache_level_1d];
639 	struct cpuinfo_cache* l3_base  = l2_base  + numbers_of_caches[cpuinfo_cache_level_2];
640 
641 	cpuinfo_log_debug(
642 		"info->Cache.GroupCount:%"PRIu32", info->Cache.GroupMask:%"PRIu32","
643 		"info->Cache.Level:%"PRIu32", info->Cache.Associativity:%"PRIu32","
644 		"info->Cache.LineSize:%"PRIu32","
645 		"info->Cache.CacheSize:%"PRIu32", info->Cache.Type:%"PRIu32"",
646 		info->Cache.GroupCount, (unsigned int)info->Cache.GroupMask.Mask,
647 		info->Cache.Level, info->Cache.Associativity, info->Cache.LineSize,
648 		info->Cache.CacheSize, info->Cache.Type);
649 
650 	struct cpuinfo_cache* current_cache = NULL;
651 	switch (info->Cache.Level) {
652 		case 1:
653 			switch (info->Cache.Type) {
654 				case CacheInstruction:
655 					current_cache = l1i_base + l1i_counter;
656 					l1i_counter++;
657 				break;
658 				case CacheData:
659 					current_cache = l1d_base + l1d_counter;
660 					l1d_counter++;
661 				break;
662 				case CacheUnified:
663 				break;
664 				case CacheTrace:
665 				break;
666 				default:
667 				break;
668 			}
669 		break;
670 		case 2:
671 			current_cache = l2_base + l2_counter;
672 			l2_counter++;
673 		break;
674 		case 3:
675 			current_cache = l3_base + l3_counter;
676 			l3_counter++;
677 		break;
678 	}
679 	current_cache->size = info->Cache.CacheSize;
680 	current_cache->line_size = info->Cache.LineSize;
681 	current_cache->associativity = info->Cache.Associativity;
682 	/* We don't have partition and set information of caches on Windows,
683 	 * so we set partitions to 1 and calculate the expected sets.
684 	 */
685 	current_cache->partitions = 1;
686 	current_cache->sets =
687 		current_cache->size / current_cache->line_size / current_cache->associativity;
688 	if (info->Cache.Type == CacheUnified) {
689 		current_cache->flags = CPUINFO_CACHE_UNIFIED;
690 	}
691 
692 	for (uint32_t i = 0; i <= info->Cache.GroupCount; i++) {
693 	/* Zero GroupCount is valid, GroupMask still can store bits set. */
694 		const uint32_t group_id = info->Cache.GroupMasks[i].Group;
695 		/* Bitmask representing processors in this group belonging to this package */
696 		KAFFINITY group_processors_mask = info->Cache.GroupMasks[i].Mask;
697 		while (group_processors_mask != 0) {
698 			const uint32_t processor_id_in_group =
699 				low_index_from_kaffinity(group_processors_mask);
700 			const uint32_t processor_global_index =
701 				global_proc_index_per_group[group_id] + processor_id_in_group;
702 
703 			store_cache_info_per_processor(
704 				processors, processor_global_index,
705 				info, current_cache);
706 
707 			/* Clear the bits in affinity mask, lower the least set bit. */
708 			group_processors_mask &= (group_processors_mask - 1);
709 		}
710 	}
711 	return true;
712 }
713 
store_package_info_per_processor(struct cpuinfo_processor * processors,const uint32_t processor_global_index,const uint32_t package_id,const uint32_t group_id,const uint32_t processor_id_in_group)714 static void store_package_info_per_processor(
715 	struct cpuinfo_processor* processors,
716 	const uint32_t processor_global_index,
717 	const uint32_t package_id,
718 	const uint32_t group_id,
719 	const uint32_t processor_id_in_group)
720 {
721 	processors[processor_global_index].windows_group_id =
722 		(uint16_t) group_id;
723 	processors[processor_global_index].windows_processor_id =
724 		(uint16_t) processor_id_in_group;
725 
726 	/* As we're counting the number of packages now, we haven't allocated memory for
727 	 * cpuinfo_packages yet, so we only set the package pointer's offset now.
728 	 */
729 	processors[processor_global_index].package =
730 		(const struct cpuinfo_package*) NULL + package_id;
731 }
732 
store_core_info_per_processor(struct cpuinfo_processor * processors,const uint32_t processor_global_index,const uint32_t core_id,PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX core_info,struct cpuinfo_core * cores,const struct woa_chip_info * chip_info)733 void store_core_info_per_processor(
734 	struct cpuinfo_processor* processors,
735 	const uint32_t processor_global_index,
736 	const uint32_t core_id,
737 	PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX core_info,
738 	struct cpuinfo_core* cores,
739 	const struct woa_chip_info *chip_info)
740 {
741 	if (cores) {
742 		processors[processor_global_index].core = cores + core_id;
743 		cores[core_id].core_id = core_id;
744 		get_core_uarch_for_efficiency(
745 			chip_info->chip_name, core_info->Processor.EfficiencyClass,
746 			&(cores[core_id].uarch), &(cores[core_id].frequency));
747 
748 		/* We don't have cluster information, so we handle it as
749 		 * fixed 1 to (cluster / cores).
750 		 * Set the cluster offset ID now, as soon as we have the
751 		 * cluster base address, we'll set the absolute address.
752 		 */
753 		processors[processor_global_index].cluster =
754 			(const struct cpuinfo_cluster*) NULL + core_id;
755 	}
756 }
757 
store_cache_info_per_processor(struct cpuinfo_processor * processors,const uint32_t processor_global_index,PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX info,struct cpuinfo_cache * current_cache)758 static void store_cache_info_per_processor(
759 	struct cpuinfo_processor* processors,
760 	const uint32_t processor_global_index,
761 	PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX info,
762 	struct cpuinfo_cache* current_cache)
763 {
764 	if (current_cache->processor_start > processor_global_index) {
765 		current_cache->processor_start = processor_global_index;
766 	}
767 	current_cache->processor_count++;
768 
769 	switch(info->Cache.Level) {
770 		case 1:
771 			switch (info->Cache.Type) {
772 				case CacheInstruction:
773 					processors[processor_global_index].cache.l1i = current_cache;
774 				break;
775 				case CacheData:
776 					processors[processor_global_index].cache.l1d = current_cache;
777 				break;
778 				case CacheUnified:
779 				break;
780 				case CacheTrace:
781 				break;
782 				default:
783 				break;
784 			}
785 		break;
786 		case 2:
787 			processors[processor_global_index].cache.l2 = current_cache;
788 		break;
789 		case 3:
790 			processors[processor_global_index].cache.l3 = current_cache;
791 		break;
792 	}
793 }
794 
connect_packages_cores_clusters_by_processors(struct cpuinfo_processor * processors,const uint32_t nr_of_processors,struct cpuinfo_package * packages,const uint32_t nr_of_packages,struct cpuinfo_cluster * clusters,struct cpuinfo_core * cores,const uint32_t nr_of_cores,const struct woa_chip_info * chip_info,enum cpuinfo_vendor vendor)795 static bool connect_packages_cores_clusters_by_processors(
796 	struct cpuinfo_processor* processors,
797 	const uint32_t nr_of_processors,
798 	struct cpuinfo_package* packages,
799 	const uint32_t nr_of_packages,
800 	struct cpuinfo_cluster* clusters,
801 	struct cpuinfo_core* cores,
802 	const uint32_t nr_of_cores,
803 	const struct woa_chip_info* chip_info,
804 	enum cpuinfo_vendor vendor)
805 {
806 	/* Adjust core and package pointers for all logical processors. */
807 	for (uint32_t i = nr_of_processors; i != 0; i--) {
808 		const uint32_t processor_id = i - 1;
809 		struct cpuinfo_processor* processor = processors + processor_id;
810 
811 		struct cpuinfo_core* core = (struct cpuinfo_core*)processor->core;
812 
813 		/* We stored the offset of pointers when we haven't allocated memory
814 		 * for packages and clusters, so now add offsets to base addresses.
815 		 */
816 		struct cpuinfo_package* package =
817 			(struct cpuinfo_package*) ((uintptr_t) packages + (uintptr_t) processor->package);
818 		if (package < packages ||
819 			package >= (packages + nr_of_packages)) {
820 			cpuinfo_log_error("invalid package indexing");
821 			return false;
822 		}
823 		processor->package = package;
824 
825 		struct cpuinfo_cluster* cluster =
826 			(struct cpuinfo_cluster*) ((uintptr_t) clusters + (uintptr_t) processor->cluster);
827 		if (cluster < clusters ||
828 			cluster >= (clusters + nr_of_cores)) {
829 			cpuinfo_log_error("invalid cluster indexing");
830 			return false;
831 		}
832 		processor->cluster = cluster;
833 
834 		if (chip_info) {
835 			strncpy_s(package->name, CPUINFO_PACKAGE_NAME_MAX, chip_info->chip_name_string,
836 				strnlen(chip_info->chip_name_string, CPUINFO_PACKAGE_NAME_MAX));
837 		}
838 
839 		/* Set start indexes and counts per packages / clusters / cores - going backwards */
840 
841 		/* This can be overwritten by lower-index processors on the same package. */
842 		package->processor_start = processor_id;
843 		package->processor_count++;
844 
845 		/* This can be overwritten by lower-index processors on the same cluster. */
846 		cluster->processor_start = processor_id;
847 		cluster->processor_count++;
848 
849 		/* This can be overwritten by lower-index processors on the same core. */
850 		core->processor_start = processor_id;
851 		core->processor_count++;
852 	}
853 	/* Fill cores */
854 	for (uint32_t i = nr_of_cores; i != 0; i--) {
855 		const uint32_t global_core_id = i - 1;
856 		struct cpuinfo_core* core = cores + global_core_id;
857 		const struct cpuinfo_processor* processor = processors + core->processor_start;
858 		struct cpuinfo_package* package = (struct cpuinfo_package*) processor->package;
859 		struct cpuinfo_cluster* cluster = (struct cpuinfo_cluster*) processor->cluster;
860 
861 		core->package = package;
862 		core->cluster = cluster;
863 		core->vendor = vendor;
864 
865 		/* This can be overwritten by lower-index cores on the same cluster/package. */
866 		cluster->core_start = global_core_id;
867 		cluster->core_count++;
868 		package->core_start = global_core_id;
869 		package->core_count++;
870 		package->cluster_start = global_core_id;
871 		package->cluster_count = package->core_count;
872 
873 		cluster->package = package;
874 		cluster->vendor = cores[cluster->core_start].vendor;
875 		cluster->uarch = cores[cluster->core_start].uarch;
876 		cluster->frequency = cores[cluster->core_start].frequency;
877 	}
878 	return true;
879 }
880 
low_index_from_kaffinity(KAFFINITY kaffinity)881 static inline uint32_t low_index_from_kaffinity(KAFFINITY kaffinity) {
882 	unsigned long index;
883 	_BitScanForward64(&index, (unsigned __int64) kaffinity);
884 	return (uint32_t) index;
885 }
886