#include #include #include #include #include #include #include enum topology_type { topology_type_invalid = 0, topology_type_smt = 1, topology_type_core = 2, }; void cpuinfo_x86_detect_topology( uint32_t max_base_index, uint32_t max_extended_index, struct cpuid_regs leaf1, struct cpuinfo_x86_topology* topology) { /* * HTT: indicates multi-core/hyper-threading support on this core. * - Intel, AMD: edx[bit 28] in basic info. */ const bool htt = !!(leaf1.edx & UINT32_C(0x10000000)); uint32_t apic_id = 0; if (htt) { apic_id = leaf1.ebx >> 24; bool amd_cmp_legacy = false; if (max_extended_index >= UINT32_C(0x80000001)) { const struct cpuid_regs leaf0x80000001 = cpuid(UINT32_C(0x80000001)); /* * CmpLegacy: core multi-processing legacy mode. * - AMD: ecx[bit 1] in extended info (reserved bit on * Intel CPUs). */ amd_cmp_legacy = !!(leaf0x80000001.ecx & UINT32_C(0x00000002)); } if (amd_cmp_legacy) { if (max_extended_index >= UINT32_C(0x80000008)) { const struct cpuid_regs leaf0x80000008 = cpuid(UINT32_C(0x80000008)); /* * NC: number of physical cores - 1. The number * of cores in the processor is NC+1. * - AMD: ecx[bits 0-7] in leaf 0x80000008 * (reserved zero bits on Intel CPUs). */ const uint32_t cores_per_processor = 1 + (leaf0x80000008.ecx & UINT32_C(0x000000FF)); topology->core_bits_length = bit_length(cores_per_processor); cpuinfo_log_debug( "HTT: APIC ID = %08" PRIx32 ", cores per processor = %" PRIu32, apic_id, cores_per_processor); } else { /* * LogicalProcessorCount: the number of cores * per processor. * - AMD: ebx[bits 16-23] in basic info * (different interpretation on Intel CPUs). */ const uint32_t cores_per_processor = (leaf1.ebx >> 16) & UINT32_C(0x000000FF); if (cores_per_processor != 0) { topology->core_bits_length = bit_length(cores_per_processor); } cpuinfo_log_debug( "HTT: APIC ID = %08" PRIx32 ", cores per processor = %" PRIu32, apic_id, cores_per_processor); } } else { /* * Maximum number of addressable IDs for logical * processors in this physical package. * - Intel: ebx[bits 16-23] in basic info (different * interpretation on AMD CPUs). */ const uint32_t logical_processors = (leaf1.ebx >> 16) & UINT32_C(0x000000FF); if (logical_processors != 0) { const uint32_t log2_max_logical_processors = bit_length(logical_processors); const uint32_t log2_max_threads_per_core = log2_max_logical_processors - topology->core_bits_length; topology->core_bits_offset = log2_max_threads_per_core; topology->thread_bits_length = log2_max_threads_per_core; } cpuinfo_log_debug( "HTT: APIC ID = %08" PRIx32 ", logical processors = %" PRIu32, apic_id, logical_processors); } } /* * x2APIC: indicated support for x2APIC feature. * - Intel: ecx[bit 21] in basic info (reserved bit on AMD CPUs). */ const bool x2apic = !!(leaf1.ecx & UINT32_C(0x00200000)); if (x2apic && (max_base_index >= UINT32_C(0xB))) { uint32_t level = 0; uint32_t type; uint32_t total_shift = 0; topology->thread_bits_offset = topology->thread_bits_length = 0; topology->core_bits_offset = topology->core_bits_length = 0; do { const struct cpuid_regs leafB = cpuidex(UINT32_C(0xB), level); type = (leafB.ecx >> 8) & UINT32_C(0x000000FF); const uint32_t level_shift = leafB.eax & UINT32_C(0x0000001F); const uint32_t x2apic_id = leafB.edx; apic_id = x2apic_id; switch (type) { case topology_type_invalid: break; case topology_type_smt: cpuinfo_log_debug( "x2 level %" PRIu32 ": APIC ID = %08" PRIx32 ", " "type SMT, shift %" PRIu32 ", total shift %" PRIu32, level, apic_id, level_shift, total_shift); topology->thread_bits_offset = total_shift; topology->thread_bits_length = level_shift; break; case topology_type_core: cpuinfo_log_debug( "x2 level %" PRIu32 ": APIC ID = %08" PRIx32 ", " "type core, shift %" PRIu32 ", total shift %" PRIu32, level, apic_id, level_shift, total_shift); topology->core_bits_offset = total_shift; topology->core_bits_length = level_shift; break; default: cpuinfo_log_warning( "unexpected topology type %" PRIu32 " (offset %" PRIu32 ", length %" PRIu32 ") " "reported in leaf 0x0000000B is ignored", type, total_shift, level_shift); break; } total_shift += level_shift; level += 1; } while (type != 0); cpuinfo_log_debug( "x2APIC ID 0x%08" PRIx32 ", " "SMT offset %" PRIu32 " length %" PRIu32 ", core offset %" PRIu32 " length %" PRIu32, apic_id, topology->thread_bits_offset, topology->thread_bits_length, topology->core_bits_offset, topology->core_bits_length); } topology->apic_id = apic_id; }