| | #include <stdint.h> |
| |
|
| | #include <cpuinfo.h> |
| | #include <x86/cpuid.h> |
| | #include <cpuinfo/utils.h> |
| | #include <cpuinfo/log.h> |
| |
|
| |
|
| | enum cache_type { |
| | cache_type_none = 0, |
| | cache_type_data = 1, |
| | cache_type_instruction = 2, |
| | cache_type_unified = 3, |
| | }; |
| |
|
| | bool cpuinfo_x86_decode_deterministic_cache_parameters( |
| | struct cpuid_regs regs, |
| | struct cpuinfo_x86_caches* cache, |
| | uint32_t* package_cores_max) |
| | { |
| | const uint32_t type = regs.eax & UINT32_C(0x1F); |
| | if (type == cache_type_none) { |
| | return false; |
| | } |
| |
|
| | |
| | const uint32_t level = (regs.eax >> 5) & UINT32_C(0x7); |
| |
|
| | const uint32_t sets = 1 + regs.ecx; |
| | const uint32_t line_size = 1 + (regs.ebx & UINT32_C(0x00000FFF)); |
| | const uint32_t partitions = 1 + ((regs.ebx >> 12) & UINT32_C(0x000003FF)); |
| | const uint32_t associativity = 1 + (regs.ebx >> 22); |
| |
|
| | *package_cores_max = 1 + (regs.eax >> 26); |
| | const uint32_t processors = 1 + ((regs.eax >> 14) & UINT32_C(0x00000FFF)); |
| | const uint32_t apic_bits = bit_length(processors); |
| |
|
| | uint32_t flags = 0; |
| | if (regs.edx & UINT32_C(0x00000002)) { |
| | flags |= CPUINFO_CACHE_INCLUSIVE; |
| | } |
| | if (regs.edx & UINT32_C(0x00000004)) { |
| | flags |= CPUINFO_CACHE_COMPLEX_INDEXING; |
| | } |
| | switch (level) { |
| | case 1: |
| | switch (type) { |
| | case cache_type_unified: |
| | cache->l1d = cache->l1i = (struct cpuinfo_x86_cache) { |
| | .size = associativity * partitions * line_size * sets, |
| | .associativity = associativity, |
| | .sets = sets, |
| | .partitions = partitions, |
| | .line_size = line_size, |
| | .flags = flags | CPUINFO_CACHE_UNIFIED, |
| | .apic_bits = apic_bits |
| | }; |
| | break; |
| | case cache_type_data: |
| | cache->l1d = (struct cpuinfo_x86_cache) { |
| | .size = associativity * partitions * line_size * sets, |
| | .associativity = associativity, |
| | .sets = sets, |
| | .partitions = partitions, |
| | .line_size = line_size, |
| | .flags = flags, |
| | .apic_bits = apic_bits |
| | }; |
| | break; |
| | case cache_type_instruction: |
| | cache->l1i = (struct cpuinfo_x86_cache) { |
| | .size = associativity * partitions * line_size * sets, |
| | .associativity = associativity, |
| | .sets = sets, |
| | .partitions = partitions, |
| | .line_size = line_size, |
| | .flags = flags, |
| | .apic_bits = apic_bits |
| | }; |
| | break; |
| | } |
| | break; |
| | case 2: |
| | switch (type) { |
| | case cache_type_instruction: |
| | cpuinfo_log_warning("unexpected L2 instruction cache reported in leaf 0x00000004 is ignored"); |
| | break; |
| | case cache_type_unified: |
| | flags |= CPUINFO_CACHE_UNIFIED; |
| | case cache_type_data: |
| | cache->l2 = (struct cpuinfo_x86_cache) { |
| | .size = associativity * partitions * line_size * sets, |
| | .associativity = associativity, |
| | .sets = sets, |
| | .partitions = partitions, |
| | .line_size = line_size, |
| | .flags = flags, |
| | .apic_bits = apic_bits |
| | }; |
| | break; |
| | } |
| | break; |
| | case 3: |
| | switch (type) { |
| | case cache_type_instruction: |
| | cpuinfo_log_warning("unexpected L3 instruction cache reported in leaf 0x00000004 is ignored"); |
| | break; |
| | case cache_type_unified: |
| | flags |= CPUINFO_CACHE_UNIFIED; |
| | case cache_type_data: |
| | cache->l3 = (struct cpuinfo_x86_cache) { |
| | .size = associativity * partitions * line_size * sets, |
| | .associativity = associativity, |
| | .sets = sets, |
| | .partitions = partitions, |
| | .line_size = line_size, |
| | .flags = flags, |
| | .apic_bits = apic_bits |
| | }; |
| | break; |
| | } |
| | break; |
| | case 4: |
| | switch (type) { |
| | case cache_type_instruction: |
| | cpuinfo_log_warning("unexpected L4 instruction cache reported in leaf 0x00000004 is ignored"); |
| | break; |
| | case cache_type_unified: |
| | flags |= CPUINFO_CACHE_UNIFIED; |
| | case cache_type_data: |
| | cache->l4 = (struct cpuinfo_x86_cache) { |
| | .size = associativity * partitions * line_size * sets, |
| | .associativity = associativity, |
| | .sets = sets, |
| | .partitions = partitions, |
| | .line_size = line_size, |
| | .flags = flags, |
| | .apic_bits = apic_bits |
| | }; |
| | break; |
| | } |
| | break; |
| | default: |
| | cpuinfo_log_warning("unexpected L%"PRIu32" cache reported in leaf 0x00000004 is ignored", level); |
| | break; |
| | } |
| | return true; |
| | } |
| |
|
| |
|
| | bool cpuinfo_x86_decode_cache_properties( |
| | struct cpuid_regs regs, |
| | struct cpuinfo_x86_caches* cache) |
| | { |
| | const uint32_t type = regs.eax & UINT32_C(0x1F); |
| | if (type == cache_type_none) { |
| | return false; |
| | } |
| |
|
| | const uint32_t level = (regs.eax >> 5) & UINT32_C(0x7); |
| | const uint32_t cores = 1 + ((regs.eax >> 14) & UINT32_C(0x00000FFF)); |
| | const uint32_t apic_bits = bit_length(cores); |
| |
|
| | const uint32_t sets = 1 + regs.ecx; |
| | const uint32_t line_size = 1 + (regs.ebx & UINT32_C(0x00000FFF)); |
| | const uint32_t partitions = 1 + ((regs.ebx >> 12) & UINT32_C(0x000003FF)); |
| | const uint32_t associativity = 1 + (regs.ebx >> 22); |
| |
|
| | uint32_t flags = 0; |
| | if (regs.edx & UINT32_C(0x00000002)) { |
| | flags |= CPUINFO_CACHE_INCLUSIVE; |
| | } |
| |
|
| | switch (level) { |
| | case 1: |
| | switch (type) { |
| | case cache_type_unified: |
| | cache->l1d = cache->l1i = (struct cpuinfo_x86_cache) { |
| | .size = associativity * partitions * line_size * sets, |
| | .associativity = associativity, |
| | .sets = sets, |
| | .partitions = partitions, |
| | .line_size = line_size, |
| | .flags = flags | CPUINFO_CACHE_UNIFIED, |
| | .apic_bits = apic_bits |
| | }; |
| | break; |
| | case cache_type_data: |
| | cache->l1d = (struct cpuinfo_x86_cache) { |
| | .size = associativity * partitions * line_size * sets, |
| | .associativity = associativity, |
| | .sets = sets, |
| | .partitions = partitions, |
| | .line_size = line_size, |
| | .flags = flags, |
| | .apic_bits = apic_bits |
| | }; |
| | break; |
| | case cache_type_instruction: |
| | cache->l1i = (struct cpuinfo_x86_cache) { |
| | .size = associativity * partitions * line_size * sets, |
| | .associativity = associativity, |
| | .sets = sets, |
| | .partitions = partitions, |
| | .line_size = line_size, |
| | .flags = flags, |
| | .apic_bits = apic_bits |
| | }; |
| | break; |
| | } |
| | break; |
| | case 2: |
| | switch (type) { |
| | case cache_type_instruction: |
| | cpuinfo_log_warning("unexpected L2 instruction cache reported in leaf 0x8000001D is ignored"); |
| | break; |
| | case cache_type_unified: |
| | flags |= CPUINFO_CACHE_UNIFIED; |
| | case cache_type_data: |
| | cache->l2 = (struct cpuinfo_x86_cache) { |
| | .size = associativity * partitions * line_size * sets, |
| | .associativity = associativity, |
| | .sets = sets, |
| | .partitions = partitions, |
| | .line_size = line_size, |
| | .flags = flags, |
| | .apic_bits = apic_bits |
| | }; |
| | break; |
| | } |
| | break; |
| | case 3: |
| | switch (type) { |
| | case cache_type_instruction: |
| | cpuinfo_log_warning("unexpected L3 instruction cache reported in leaf 0x8000001D is ignored"); |
| | break; |
| | case cache_type_unified: |
| | flags |= CPUINFO_CACHE_UNIFIED; |
| | case cache_type_data: |
| | cache->l3 = (struct cpuinfo_x86_cache) { |
| | .size = associativity * partitions * line_size * sets, |
| | .associativity = associativity, |
| | .sets = sets, |
| | .partitions = partitions, |
| | .line_size = line_size, |
| | .flags = flags, |
| | .apic_bits = apic_bits |
| | }; |
| | break; |
| | } |
| | break; |
| | default: |
| | cpuinfo_log_warning("unexpected L%"PRIu32" cache reported in leaf 0x8000001D is ignored", level); |
| | break; |
| | } |
| | return true; |
| | } |
| |
|