• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <stdint.h>
2 #include <stddef.h>
3 #include <stdlib.h>
4 #include <string.h>
5 
6 #include <cpuinfo.h>
7 #include <x86/api.h>
8 #include <cpuinfo/internal-api.h>
9 #include <cpuinfo/log.h>
10 
11 #include <windows.h>
12 
13 #ifdef __GNUC__
14   #define CPUINFO_ALLOCA __builtin_alloca
15 #else
16   #define CPUINFO_ALLOCA _alloca
17 #endif
18 
19 
bit_mask(uint32_t bits)20 static inline uint32_t bit_mask(uint32_t bits) {
21 	return (UINT32_C(1) << bits) - UINT32_C(1);
22 }
23 
low_index_from_kaffinity(KAFFINITY kaffinity)24 static inline uint32_t low_index_from_kaffinity(KAFFINITY kaffinity) {
25 	#if defined(_M_X64) || defined(_M_AMD64)
26 		unsigned long index;
27 		_BitScanForward64(&index, (unsigned __int64) kaffinity);
28 		return (uint32_t) index;
29 	#elif defined(_M_IX86)
30 		unsigned long index;
31 		_BitScanForward(&index, (unsigned long) kaffinity);
32 		return (uint32_t) index;
33 	#else
34 		#error Platform-specific implementation required
35 	#endif
36 }
37 
cpuinfo_x86_count_caches(uint32_t processors_count,const struct cpuinfo_processor * processors,const struct cpuinfo_x86_processor * x86_processor,uint32_t * l1i_count_ptr,uint32_t * l1d_count_ptr,uint32_t * l2_count_ptr,uint32_t * l3_count_ptr,uint32_t * l4_count_ptr)38 static void cpuinfo_x86_count_caches(
39 	uint32_t processors_count,
40 	const struct cpuinfo_processor* processors,
41 	const struct cpuinfo_x86_processor* x86_processor,
42 	uint32_t* l1i_count_ptr,
43 	uint32_t* l1d_count_ptr,
44 	uint32_t* l2_count_ptr,
45 	uint32_t* l3_count_ptr,
46 	uint32_t* l4_count_ptr)
47 {
48 	uint32_t l1i_count = 0, l1d_count = 0, l2_count = 0, l3_count = 0, l4_count = 0;
49 	uint32_t last_l1i_id = UINT32_MAX, last_l1d_id = UINT32_MAX;
50 	uint32_t last_l2_id = UINT32_MAX, last_l3_id = UINT32_MAX, last_l4_id = UINT32_MAX;
51 	for (uint32_t i = 0; i < processors_count; i++) {
52 		const uint32_t apic_id = processors[i].apic_id;
53 		cpuinfo_log_debug("APID ID %"PRIu32": logical processor %"PRIu32, apic_id, i);
54 
55 		if (x86_processor->cache.l1i.size != 0) {
56 			const uint32_t l1i_id = apic_id & ~bit_mask(x86_processor->cache.l1i.apic_bits);
57 			if (l1i_id != last_l1i_id) {
58 				last_l1i_id = l1i_id;
59 				l1i_count++;
60 			}
61 		}
62 		if (x86_processor->cache.l1d.size != 0) {
63 			const uint32_t l1d_id = apic_id & ~bit_mask(x86_processor->cache.l1d.apic_bits);
64 			if (l1d_id != last_l1d_id) {
65 				last_l1d_id = l1d_id;
66 				l1d_count++;
67 			}
68 		}
69 		if (x86_processor->cache.l2.size != 0) {
70 			const uint32_t l2_id = apic_id & ~bit_mask(x86_processor->cache.l2.apic_bits);
71 			if (l2_id != last_l2_id) {
72 				last_l2_id = l2_id;
73 				l2_count++;
74 			}
75 		}
76 		if (x86_processor->cache.l3.size != 0) {
77 			const uint32_t l3_id = apic_id & ~bit_mask(x86_processor->cache.l3.apic_bits);
78 			if (l3_id != last_l3_id) {
79 				last_l3_id = l3_id;
80 				l3_count++;
81 			}
82 		}
83 		if (x86_processor->cache.l4.size != 0) {
84 			const uint32_t l4_id = apic_id & ~bit_mask(x86_processor->cache.l4.apic_bits);
85 			if (l4_id != last_l4_id) {
86 				last_l4_id = l4_id;
87 				l4_count++;
88 			}
89 		}
90 	}
91 	*l1i_count_ptr = l1i_count;
92 	*l1d_count_ptr = l1d_count;
93 	*l2_count_ptr  = l2_count;
94 	*l3_count_ptr  = l3_count;
95 	*l4_count_ptr  = l4_count;
96 }
97 
cpuinfo_x86_windows_is_wine(void)98 static bool cpuinfo_x86_windows_is_wine(void) {
99 	HMODULE ntdll = GetModuleHandleW(L"ntdll.dll");
100 	if (ntdll == NULL) {
101 		return false;
102 	}
103 
104 	return GetProcAddress(ntdll, "wine_get_version") != NULL;
105 }
106 
cpuinfo_x86_windows_init(PINIT_ONCE init_once,PVOID parameter,PVOID * context)107 BOOL CALLBACK cpuinfo_x86_windows_init(PINIT_ONCE init_once, PVOID parameter, PVOID* context) {
108 	struct cpuinfo_processor* processors = NULL;
109 	struct cpuinfo_core* cores = NULL;
110 	struct cpuinfo_cluster* clusters = NULL;
111 	struct cpuinfo_package* packages = NULL;
112 	struct cpuinfo_cache* l1i = NULL;
113 	struct cpuinfo_cache* l1d = NULL;
114 	struct cpuinfo_cache* l2 = NULL;
115 	struct cpuinfo_cache* l3 = NULL;
116 	struct cpuinfo_cache* l4 = NULL;
117 	PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX processor_infos = NULL;
118 
119 	HANDLE heap = GetProcessHeap();
120 	const bool is_wine = cpuinfo_x86_windows_is_wine();
121 
122 	struct cpuinfo_x86_processor x86_processor;
123 	ZeroMemory(&x86_processor, sizeof(x86_processor));
124 	cpuinfo_x86_init_processor(&x86_processor);
125 	char brand_string[48];
126 	cpuinfo_x86_normalize_brand_string(x86_processor.brand_string, brand_string);
127 
128 	const uint32_t thread_bits_mask = bit_mask(x86_processor.topology.thread_bits_length);
129 	const uint32_t core_bits_mask   = bit_mask(x86_processor.topology.core_bits_length);
130 	const uint32_t package_bits_offset = max(
131 		x86_processor.topology.thread_bits_offset + x86_processor.topology.thread_bits_length,
132 		x86_processor.topology.core_bits_offset + x86_processor.topology.core_bits_length);
133 
134 	/* WINE doesn't implement GetMaximumProcessorGroupCount and aborts when calling it */
135 	const uint32_t max_group_count = is_wine ? 1 : (uint32_t) GetMaximumProcessorGroupCount();
136 	cpuinfo_log_debug("detected %"PRIu32" processor groups", max_group_count);
137 
138 	uint32_t processors_count = 0;
139 	uint32_t* processors_per_group = (uint32_t*) CPUINFO_ALLOCA(max_group_count * sizeof(uint32_t));
140 	for (uint32_t i = 0; i < max_group_count; i++) {
141 		processors_per_group[i] = GetMaximumProcessorCount((WORD) i);
142 		cpuinfo_log_debug("detected %"PRIu32" processors in group %"PRIu32,
143 			processors_per_group[i], i);
144 		processors_count += processors_per_group[i];
145 	}
146 
147 	uint32_t* processors_before_group = (uint32_t*) CPUINFO_ALLOCA(max_group_count * sizeof(uint32_t));
148 	for (uint32_t i = 0, count = 0; i < max_group_count; i++) {
149 		processors_before_group[i] = count;
150 		cpuinfo_log_debug("detected %"PRIu32" processors before group %"PRIu32,
151 			processors_before_group[i], i);
152 		count += processors_per_group[i];
153 	}
154 
155 	processors = HeapAlloc(heap, HEAP_ZERO_MEMORY, processors_count * sizeof(struct cpuinfo_processor));
156 	if (processors == NULL) {
157 		cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" logical processors",
158 			processors_count * sizeof(struct cpuinfo_processor), processors_count);
159 		goto cleanup;
160 	}
161 
162 	DWORD cores_info_size = 0;
163 	if (GetLogicalProcessorInformationEx(RelationProcessorCore, NULL, &cores_info_size) == FALSE) {
164 		const DWORD last_error = GetLastError();
165 		if (last_error != ERROR_INSUFFICIENT_BUFFER) {
166 			cpuinfo_log_error("failed to query size of processor cores information: error %"PRIu32,
167 				(uint32_t) last_error);
168 			goto cleanup;
169 		}
170 	}
171 
172 	DWORD packages_info_size = 0;
173 	if (GetLogicalProcessorInformationEx(RelationProcessorPackage, NULL, &packages_info_size) == FALSE) {
174 		const DWORD last_error = GetLastError();
175 		if (last_error != ERROR_INSUFFICIENT_BUFFER) {
176 			cpuinfo_log_error("failed to query size of processor packages information: error %"PRIu32,
177 				(uint32_t) last_error);
178 			goto cleanup;
179 		}
180 	}
181 
182 	DWORD max_info_size = max(cores_info_size, packages_info_size);
183 
184 	processor_infos = HeapAlloc(heap, 0, max_info_size);
185 	if (processor_infos == NULL) {
186 		cpuinfo_log_error("failed to allocate %"PRIu32" bytes for logical processor information",
187 			(uint32_t) max_info_size);
188 		goto cleanup;
189 	}
190 
191 	if (GetLogicalProcessorInformationEx(RelationProcessorPackage, processor_infos, &max_info_size) == FALSE) {
192 		cpuinfo_log_error("failed to query processor packages information: error %"PRIu32,
193 			(uint32_t) GetLastError());
194 		goto cleanup;
195 	}
196 
197 	uint32_t packages_count = 0;
198 	PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX packages_info_end =
199 		(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX) ((uintptr_t) processor_infos + packages_info_size);
200 	for (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX package_info = processor_infos;
201 		package_info < packages_info_end;
202 		package_info = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX) ((uintptr_t) package_info + package_info->Size))
203 	{
204 		if (package_info->Relationship != RelationProcessorPackage) {
205 			cpuinfo_log_warning("unexpected processor info type (%"PRIu32") for processor package information",
206 				(uint32_t) package_info->Relationship);
207 			continue;
208 		}
209 
210 		/* We assume that packages are reported in APIC order */
211 		const uint32_t package_id = packages_count++;
212 		/* Reconstruct package part of APIC ID */
213 		const uint32_t package_apic_id = package_id << package_bits_offset;
214 		/* Iterate processor groups and set the package part of APIC ID */
215 		for (uint32_t i = 0; i < package_info->Processor.GroupCount; i++) {
216 			const uint32_t group_id = package_info->Processor.GroupMask[i].Group;
217 			/* Global index of the first logical processor belonging to this group */
218 			const uint32_t group_processors_start = processors_before_group[group_id];
219 			/* Bitmask representing processors in this group belonging to this package */
220 			KAFFINITY group_processors_mask = package_info->Processor.GroupMask[i].Mask;
221 			while (group_processors_mask != 0) {
222 				const uint32_t group_processor_id = low_index_from_kaffinity(group_processors_mask);
223 				const uint32_t processor_id = group_processors_start + group_processor_id;
224 				processors[processor_id].package = (const struct cpuinfo_package*) NULL + package_id;
225 				processors[processor_id].windows_group_id = (uint16_t) group_id;
226 				processors[processor_id].windows_processor_id = (uint16_t) group_processor_id;
227 				processors[processor_id].apic_id = package_apic_id;
228 
229 				/* Reset the lowest bit in affinity mask */
230 				group_processors_mask &= (group_processors_mask - 1);
231 			}
232 		}
233 	}
234 
235 	max_info_size = max(cores_info_size, packages_info_size);
236 	if (GetLogicalProcessorInformationEx(RelationProcessorCore, processor_infos, &max_info_size) == FALSE) {
237 		cpuinfo_log_error("failed to query processor cores information: error %"PRIu32,
238 			(uint32_t) GetLastError());
239 		goto cleanup;
240 	}
241 
242 	uint32_t cores_count = 0;
243 	/* Index (among all cores) of the the first core on the current package */
244 	uint32_t package_core_start = 0;
245 	uint32_t current_package_apic_id = 0;
246 	PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX cores_info_end =
247 		(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX) ((uintptr_t) processor_infos + cores_info_size);
248 	for (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX core_info = processor_infos;
249 		core_info < cores_info_end;
250 		core_info = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX) ((uintptr_t) core_info + core_info->Size))
251 	{
252 		if (core_info->Relationship != RelationProcessorCore) {
253 			cpuinfo_log_warning("unexpected processor info type (%"PRIu32") for processor core information",
254 				(uint32_t) core_info->Relationship);
255 			continue;
256 		}
257 
258 		/* We assume that cores and logical processors are reported in APIC order */
259 		const uint32_t core_id = cores_count++;
260 		uint32_t smt_id = 0;
261 		/* Reconstruct core part of APIC ID */
262 		const uint32_t core_apic_id = (core_id & core_bits_mask) << x86_processor.topology.core_bits_offset;
263 		/* Iterate processor groups and set the core & SMT parts of APIC ID */
264 		for (uint32_t i = 0; i < core_info->Processor.GroupCount; i++) {
265 			const uint32_t group_id = core_info->Processor.GroupMask[i].Group;
266 			/* Global index of the first logical processor belonging to this group */
267 			const uint32_t group_processors_start = processors_before_group[group_id];
268 			/* Bitmask representing processors in this group belonging to this package */
269 			KAFFINITY group_processors_mask = core_info->Processor.GroupMask[i].Mask;
270 			while (group_processors_mask != 0) {
271 				const uint32_t group_processor_id = low_index_from_kaffinity(group_processors_mask);
272 				const uint32_t processor_id = group_processors_start + group_processor_id;
273 
274 				/* Check if this is the first core on a new package */
275 				if (processors[processor_id].apic_id != current_package_apic_id) {
276 					package_core_start = core_id;
277 					current_package_apic_id = processors[processor_id].apic_id;
278 				}
279 				/* Core ID w.r.t package */
280 				const uint32_t package_core_id = core_id - package_core_start;
281 
282 				/* Update APIC ID with core and SMT parts */
283 				processors[processor_id].apic_id |=
284 					((smt_id & thread_bits_mask) << x86_processor.topology.thread_bits_offset) |
285 					((package_core_id & core_bits_mask) << x86_processor.topology.core_bits_offset);
286 				cpuinfo_log_debug("reconstructed APIC ID 0x%08"PRIx32" for processor %"PRIu32" in group %"PRIu32,
287 					processors[processor_id].apic_id, group_processor_id, group_id);
288 
289 				/* Set SMT ID (assume logical processors within the core are reported in APIC order) */
290 				processors[processor_id].smt_id = smt_id++;
291 				processors[processor_id].core = (const struct cpuinfo_core*) NULL + core_id;
292 
293 				/* Reset the lowest bit in affinity mask */
294 				group_processors_mask &= (group_processors_mask - 1);
295 			}
296 		}
297 	}
298 
299 	cores = HeapAlloc(heap, HEAP_ZERO_MEMORY, cores_count * sizeof(struct cpuinfo_core));
300 	if (cores == NULL) {
301 		cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" cores",
302 			cores_count * sizeof(struct cpuinfo_core), cores_count);
303 		goto cleanup;
304 	}
305 
306 	clusters = HeapAlloc(heap, HEAP_ZERO_MEMORY, packages_count * sizeof(struct cpuinfo_cluster));
307 	if (clusters == NULL) {
308 		cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" core clusters",
309 			packages_count * sizeof(struct cpuinfo_cluster), packages_count);
310 		goto cleanup;
311 	}
312 
313 	packages = HeapAlloc(heap, HEAP_ZERO_MEMORY, packages_count * sizeof(struct cpuinfo_package));
314 	if (packages == NULL) {
315 		cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" physical packages",
316 			packages_count * sizeof(struct cpuinfo_package), packages_count);
317 		goto cleanup;
318 	}
319 
320 	for (uint32_t i = processors_count; i != 0; i--) {
321 		const uint32_t processor_id = i - 1;
322 		struct cpuinfo_processor* processor = processors + processor_id;
323 
324 		/* Adjust core and package pointers for all logical processors */
325 		struct cpuinfo_core* core =
326 			(struct cpuinfo_core*) ((uintptr_t) cores + (uintptr_t) processor->core);
327 		processor->core = core;
328 		struct cpuinfo_cluster* cluster =
329 			(struct cpuinfo_cluster*) ((uintptr_t) clusters + (uintptr_t) processor->cluster);
330 		processor->cluster = cluster;
331 		struct cpuinfo_package* package =
332 			(struct cpuinfo_package*) ((uintptr_t) packages + (uintptr_t) processor->package);
333 		processor->package = package;
334 
335 		/* This can be overwritten by lower-index processors on the same package */
336 		package->processor_start = processor_id;
337 		package->processor_count += 1;
338 
339 		/* This can be overwritten by lower-index processors on the same cluster */
340 		cluster->processor_start = processor_id;
341 		cluster->processor_count += 1;
342 
343 		/* This can be overwritten by lower-index processors on the same core*/
344 		core->processor_start = processor_id;
345 		core->processor_count += 1;
346 	}
347 
348 	/* Set vendor/uarch/CPUID information for cores */
349 	for (uint32_t i = cores_count; i != 0; i--) {
350 		const uint32_t global_core_id = i - 1;
351 		struct cpuinfo_core* core = cores + global_core_id;
352 		const struct cpuinfo_processor* processor = processors + core->processor_start;
353 		struct cpuinfo_package* package = (struct cpuinfo_package*) processor->package;
354 		struct cpuinfo_cluster* cluster = (struct cpuinfo_cluster*) processor->cluster;
355 
356 		core->cluster = cluster;
357 		core->package = package;
358 		core->core_id = core_bits_mask &
359 			(processor->apic_id >> x86_processor.topology.core_bits_offset);
360 		core->vendor = x86_processor.vendor;
361 		core->uarch  = x86_processor.uarch;
362 		core->cpuid  = x86_processor.cpuid;
363 
364 		/* This can be overwritten by lower-index cores on the same cluster/package */
365 		cluster->core_start = global_core_id;
366 		cluster->core_count += 1;
367 		package->core_start = global_core_id;
368 		package->core_count += 1;
369 	}
370 
371 	for (uint32_t i = 0; i < packages_count; i++) {
372 		struct cpuinfo_package* package = packages + i;
373 		struct cpuinfo_cluster* cluster = clusters + i;
374 
375 		cluster->package = package;
376 		cluster->vendor = cores[cluster->core_start].vendor;
377 		cluster->uarch = cores[cluster->core_start].uarch;
378 		cluster->cpuid = cores[cluster->core_start].cpuid;
379 		package->cluster_start = i;
380 		package->cluster_count = 1;
381 		cpuinfo_x86_format_package_name(x86_processor.vendor, brand_string, package->name);
382 	}
383 
384 	/* Count caches */
385 	uint32_t l1i_count, l1d_count, l2_count, l3_count, l4_count;
386 	cpuinfo_x86_count_caches(processors_count, processors, &x86_processor,
387 		&l1i_count, &l1d_count, &l2_count, &l3_count, &l4_count);
388 
389 	/* Allocate cache descriptions */
390 	if (l1i_count != 0) {
391 		l1i = HeapAlloc(heap, HEAP_ZERO_MEMORY, l1i_count * sizeof(struct cpuinfo_cache));
392 		if (l1i == NULL) {
393 			cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" L1I caches",
394 				l1i_count * sizeof(struct cpuinfo_cache), l1i_count);
395 			goto cleanup;
396 		}
397 	}
398 	if (l1d_count != 0) {
399 		l1d = HeapAlloc(heap, HEAP_ZERO_MEMORY, l1d_count * sizeof(struct cpuinfo_cache));
400 		if (l1d == NULL) {
401 			cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" L1D caches",
402 				l1d_count * sizeof(struct cpuinfo_cache), l1d_count);
403 			goto cleanup;
404 		}
405 	}
406 	if (l2_count != 0) {
407 		l2 = HeapAlloc(heap, HEAP_ZERO_MEMORY, l2_count * sizeof(struct cpuinfo_cache));
408 		if (l2 == NULL) {
409 			cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" L2 caches",
410 				l2_count * sizeof(struct cpuinfo_cache), l2_count);
411 			goto cleanup;
412 		}
413 	}
414 	if (l3_count != 0) {
415 		l3 = HeapAlloc(heap, HEAP_ZERO_MEMORY, l3_count * sizeof(struct cpuinfo_cache));
416 		if (l3 == NULL) {
417 			cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" L3 caches",
418 				l3_count * sizeof(struct cpuinfo_cache), l3_count);
419 			goto cleanup;
420 		}
421 	}
422 	if (l4_count != 0) {
423 		l4 = HeapAlloc(heap, HEAP_ZERO_MEMORY, l4_count * sizeof(struct cpuinfo_cache));
424 		if (l4 == NULL) {
425 			cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" L4 caches",
426 				l4_count * sizeof(struct cpuinfo_cache), l4_count);
427 			goto cleanup;
428 		}
429 	}
430 
431 	/* Set cache information */
432 	uint32_t l1i_index = UINT32_MAX, l1d_index = UINT32_MAX, l2_index = UINT32_MAX, l3_index = UINT32_MAX, l4_index = UINT32_MAX;
433 	uint32_t last_l1i_id = UINT32_MAX, last_l1d_id = UINT32_MAX;
434 	uint32_t last_l2_id = UINT32_MAX, last_l3_id = UINT32_MAX, last_l4_id = UINT32_MAX;
435 	for (uint32_t i = 0; i < processors_count; i++) {
436 		const uint32_t apic_id = processors[i].apic_id;
437 
438 		if (x86_processor.cache.l1i.size != 0) {
439 			const uint32_t l1i_id = apic_id & ~bit_mask(x86_processor.cache.l1i.apic_bits);
440 			processors[i].cache.l1i = &l1i[l1i_index];
441 			if (l1i_id != last_l1i_id) {
442 				/* new cache */
443 				last_l1i_id = l1i_id;
444 				l1i[++l1i_index] = (struct cpuinfo_cache) {
445 					.size            = x86_processor.cache.l1i.size,
446 					.associativity   = x86_processor.cache.l1i.associativity,
447 					.sets            = x86_processor.cache.l1i.sets,
448 					.partitions      = x86_processor.cache.l1i.partitions,
449 					.line_size       = x86_processor.cache.l1i.line_size,
450 					.flags           = x86_processor.cache.l1i.flags,
451 					.processor_start = i,
452 					.processor_count = 1,
453 				};
454 			} else {
455 				/* another processor sharing the same cache */
456 				l1i[l1i_index].processor_count += 1;
457 			}
458 			processors[i].cache.l1i = &l1i[l1i_index];
459 		} else {
460 			/* reset cache id */
461 			last_l1i_id = UINT32_MAX;
462 		}
463 		if (x86_processor.cache.l1d.size != 0) {
464 			const uint32_t l1d_id = apic_id & ~bit_mask(x86_processor.cache.l1d.apic_bits);
465 			processors[i].cache.l1d = &l1d[l1d_index];
466 			if (l1d_id != last_l1d_id) {
467 				/* new cache */
468 				last_l1d_id = l1d_id;
469 				l1d[++l1d_index] = (struct cpuinfo_cache) {
470 					.size            = x86_processor.cache.l1d.size,
471 					.associativity   = x86_processor.cache.l1d.associativity,
472 					.sets            = x86_processor.cache.l1d.sets,
473 					.partitions      = x86_processor.cache.l1d.partitions,
474 					.line_size       = x86_processor.cache.l1d.line_size,
475 					.flags           = x86_processor.cache.l1d.flags,
476 					.processor_start = i,
477 					.processor_count = 1,
478 				};
479 			} else {
480 				/* another processor sharing the same cache */
481 				l1d[l1d_index].processor_count += 1;
482 			}
483 			processors[i].cache.l1d = &l1d[l1d_index];
484 		} else {
485 			/* reset cache id */
486 			last_l1d_id = UINT32_MAX;
487 		}
488 		if (x86_processor.cache.l2.size != 0) {
489 			const uint32_t l2_id = apic_id & ~bit_mask(x86_processor.cache.l2.apic_bits);
490 			processors[i].cache.l2 = &l2[l2_index];
491 			if (l2_id != last_l2_id) {
492 				/* new cache */
493 				last_l2_id = l2_id;
494 				l2[++l2_index] = (struct cpuinfo_cache) {
495 					.size            = x86_processor.cache.l2.size,
496 					.associativity   = x86_processor.cache.l2.associativity,
497 					.sets            = x86_processor.cache.l2.sets,
498 					.partitions      = x86_processor.cache.l2.partitions,
499 					.line_size       = x86_processor.cache.l2.line_size,
500 					.flags           = x86_processor.cache.l2.flags,
501 					.processor_start = i,
502 					.processor_count = 1,
503 				};
504 			} else {
505 				/* another processor sharing the same cache */
506 				l2[l2_index].processor_count += 1;
507 			}
508 			processors[i].cache.l2 = &l2[l2_index];
509 		} else {
510 			/* reset cache id */
511 			last_l2_id = UINT32_MAX;
512 		}
513 		if (x86_processor.cache.l3.size != 0) {
514 			const uint32_t l3_id = apic_id & ~bit_mask(x86_processor.cache.l3.apic_bits);
515 			processors[i].cache.l3 = &l3[l3_index];
516 			if (l3_id != last_l3_id) {
517 				/* new cache */
518 				last_l3_id = l3_id;
519 				l3[++l3_index] = (struct cpuinfo_cache) {
520 					.size            = x86_processor.cache.l3.size,
521 					.associativity   = x86_processor.cache.l3.associativity,
522 					.sets            = x86_processor.cache.l3.sets,
523 					.partitions      = x86_processor.cache.l3.partitions,
524 					.line_size       = x86_processor.cache.l3.line_size,
525 					.flags           = x86_processor.cache.l3.flags,
526 					.processor_start = i,
527 					.processor_count = 1,
528 				};
529 			} else {
530 				/* another processor sharing the same cache */
531 				l3[l3_index].processor_count += 1;
532 			}
533 			processors[i].cache.l3 = &l3[l3_index];
534 		} else {
535 			/* reset cache id */
536 			last_l3_id = UINT32_MAX;
537 		}
538 		if (x86_processor.cache.l4.size != 0) {
539 			const uint32_t l4_id = apic_id & ~bit_mask(x86_processor.cache.l4.apic_bits);
540 			processors[i].cache.l4 = &l4[l4_index];
541 			if (l4_id != last_l4_id) {
542 				/* new cache */
543 				last_l4_id = l4_id;
544 				l4[++l4_index] = (struct cpuinfo_cache) {
545 					.size            = x86_processor.cache.l4.size,
546 					.associativity   = x86_processor.cache.l4.associativity,
547 					.sets            = x86_processor.cache.l4.sets,
548 					.partitions      = x86_processor.cache.l4.partitions,
549 					.line_size       = x86_processor.cache.l4.line_size,
550 					.flags           = x86_processor.cache.l4.flags,
551 					.processor_start = i,
552 					.processor_count = 1,
553 				};
554 			} else {
555 				/* another processor sharing the same cache */
556 				l4[l4_index].processor_count += 1;
557 			}
558 			processors[i].cache.l4 = &l4[l4_index];
559 		} else {
560 			/* reset cache id */
561 			last_l4_id = UINT32_MAX;
562 		}
563 	}
564 
565 
566 	/* Commit changes */
567 	cpuinfo_processors = processors;
568 	cpuinfo_cores = cores;
569 	cpuinfo_clusters = clusters;
570 	cpuinfo_packages = packages;
571 	cpuinfo_cache[cpuinfo_cache_level_1i] = l1i;
572 	cpuinfo_cache[cpuinfo_cache_level_1d] = l1d;
573 	cpuinfo_cache[cpuinfo_cache_level_2]  = l2;
574 	cpuinfo_cache[cpuinfo_cache_level_3]  = l3;
575 	cpuinfo_cache[cpuinfo_cache_level_4]  = l4;
576 
577 	cpuinfo_processors_count = processors_count;
578 	cpuinfo_cores_count = cores_count;
579 	cpuinfo_clusters_count = packages_count;
580 	cpuinfo_packages_count = packages_count;
581 	cpuinfo_cache_count[cpuinfo_cache_level_1i] = l1i_count;
582 	cpuinfo_cache_count[cpuinfo_cache_level_1d] = l1d_count;
583 	cpuinfo_cache_count[cpuinfo_cache_level_2]  = l2_count;
584 	cpuinfo_cache_count[cpuinfo_cache_level_3]  = l3_count;
585 	cpuinfo_cache_count[cpuinfo_cache_level_4]  = l4_count;
586 	cpuinfo_max_cache_size = cpuinfo_compute_max_cache_size(&processors[0]);
587 
588 	cpuinfo_global_uarch = (struct cpuinfo_uarch_info) {
589 		.uarch = x86_processor.uarch,
590 		.cpuid = x86_processor.cpuid,
591 		.processor_count = processors_count,
592 		.core_count = cores_count,
593 	};
594 
595 	MemoryBarrier();
596 
597 	cpuinfo_is_initialized = true;
598 
599 	processors = NULL;
600 	cores = NULL;
601 	clusters = NULL;
602 	packages = NULL;
603 	l1i = l1d = l2 = l3 = l4 = NULL;
604 
605 cleanup:
606 	if (processors != NULL) {
607 		HeapFree(heap, 0, processors);
608 	}
609 	if (cores != NULL) {
610 		HeapFree(heap, 0, cores);
611 	}
612 	if (clusters != NULL) {
613 		HeapFree(heap, 0, clusters);
614 	}
615 	if (packages != NULL) {
616 		HeapFree(heap, 0, packages);
617 	}
618 	if (l1i != NULL) {
619 		HeapFree(heap, 0, l1i);
620 	}
621 	if (l1d != NULL) {
622 		HeapFree(heap, 0, l1d);
623 	}
624 	if (l2 != NULL) {
625 		HeapFree(heap, 0, l2);
626 	}
627 	if (l3 != NULL) {
628 		HeapFree(heap, 0, l3);
629 	}
630 	if (l4 != NULL) {
631 		HeapFree(heap, 0, l4);
632 	}
633 	return TRUE;
634 }
635