1# Copyright (C) 2021-2022 Intel Corporation. 2# 3# SPDX-License-Identifier: BSD-3-Clause 4# 5 6import logging 7import lxml.etree 8import re 9 10from cpuparser import parse_cpuid, get_online_cpu_ids 11from cpuparser.msr import * 12from extractors.helpers import add_child, get_node 13 14level_types = { 15 1: "thread", 16 2: "core", 17 3: "module", 18 4: "tile", 19 5: "die", 20} 21 22def get_parent(processors_node, topo_level, topo_id): 23 n = get_node(processors_node, f"//{topo_level}[@id='{topo_id}']") 24 return n 25 26def get_or_create_parent(processors_node, topo_level, topo_id): 27 n = get_parent(processors_node, topo_level, topo_id) 28 if n is None: 29 n = lxml.etree.Element(topo_level) 30 n.set("id", topo_id) 31 return (n, True) 32 return (n, False) 33 34def extract_model(processors_node, cpu_id, family_id, model_id, core_type, native_model_id): 35 n = get_node(processors_node, f"//model[family_id='{family_id}' and model_id='{model_id}' and core_type='{core_type}' and native_model_id='{native_model_id}']") 36 if n is None: 37 n = add_child(processors_node, "model") 38 39 add_child(n, "family_id", family_id) 40 add_child(n, "model_id", model_id) 41 add_child(n, "core_type", core_type) 42 add_child(n, "native_model_id", native_model_id) 43 44 brandstring = b"" 45 for leaf in [0x80000002, 0x80000003, 0x80000004]: 46 leaf_data = parse_cpuid(leaf, 0, cpu_id) 47 brandstring += leaf_data.brandstring 48 n.set("description", re.sub('[^!-~]+', ' ', brandstring.decode()).strip()) 49 50 leaves = [(1, 0), (6, 0), (7, 0), (0x80000001, 0), (0x80000007, 0)] 51 for leaf in leaves: 52 leaf_data = parse_cpuid(leaf[0], leaf[1], cpu_id) 53 for cap in leaf_data.capability_bits: 54 if getattr(leaf_data, cap) == 1: 55 add_child(n, "capability", id=cap) 56 57 msr_regs = [MSR_IA32_MISC_ENABLE, MSR_IA32_FEATURE_CONTROL, MSR_IA32_VMX_BASIC, 58 MSR_IA32_VMX_PINBASED_CTLS, MSR_IA32_VMX_PROCBASED_CTLS, MSR_IA32_VMX_EXIT_CTLS, 59 MSR_IA32_VMX_ENTRY_CTLS, MSR_IA32_VMX_MISC, MSR_IA32_VMX_PROCBASED_CTLS2, 60 MSR_IA32_VMX_EPT_VPID_CAP] 61 for msr_reg in msr_regs: 62 msr_data = msr_reg.rdmsr(cpu_id) 63 for cap in msr_data.capability_bits: 64 if getattr(msr_data, cap) == 1: 65 add_child(n, "capability", id=cap) 66 67 leaves = [(0, 0), (0x80000008, 0)] 68 for leaf in leaves: 69 leaf_data = parse_cpuid(leaf[0], leaf[1], cpu_id) 70 for cap in leaf_data.attribute_bits: 71 add_child(n, "attribute", str(getattr(leaf_data, cap)), id=cap) 72 73 msr_regs = [MSR_TURBO_RATIO_LIMIT, MSR_TURBO_ACTIVATION_RATIO] 74 for msr_reg in msr_regs: 75 try: 76 msr_data = msr_reg.rdmsr(cpu_id) 77 for attr in msr_data.attribute_bits: 78 add_child(n, "attribute", str(getattr(msr_data, attr)), id=attr) 79 except IOError: 80 logging.debug(f"No {msr_reg} MSR info for CPU {cpu_id}.") 81 82def extract_topology(processors_node): 83 cpu_ids = get_online_cpu_ids() 84 for cpu_id in cpu_ids: 85 subleaf = 0 86 last_shift = 0 87 last_node = None 88 89 leaf_0 = parse_cpuid(0, 0, cpu_id) 90 if leaf_0.max_leaf >= 0x1f: 91 topo_leaf = 0x1f 92 else: 93 topo_leaf = 0xb 94 95 while True: 96 leaf_topo = parse_cpuid(topo_leaf, subleaf, cpu_id) 97 if leaf_topo.level_type == 0: 98 highest_level = max(level_types.keys()) 99 if last_node.tag != level_types[highest_level]: 100 n, _ = get_or_create_parent(processors_node, level_types[highest_level], "0x0") 101 n.append(last_node) 102 last_node = n 103 processors_node.append(last_node) 104 break 105 106 topo_level = level_types[leaf_topo.level_type] 107 topo_id = hex(leaf_topo.x2apic_id >> last_shift) 108 n, created = get_or_create_parent(processors_node, topo_level, topo_id) 109 110 if last_node is None: 111 leaf_1 = parse_cpuid(1, 0, cpu_id) 112 family_id = hex(leaf_1.display_family) 113 model_id = hex(leaf_1.display_model) 114 if leaf_0.max_leaf >= 0x1a: 115 leaf_1a = parse_cpuid(0x1a, 0, cpu_id) 116 core_type = leaf_1a.core_type 117 native_model_id = hex(leaf_1a.native_model_id) 118 else: 119 core_type = "" 120 native_model_id = "" 121 122 add_child(n, "cpu_id", text=str(cpu_id)) 123 add_child(n, "apic_id", text=hex(leaf_1.initial_apic_id)) 124 add_child(n, "x2apic_id", text=hex(leaf_topo.x2apic_id)) 125 add_child(n, "family_id", text=family_id) 126 add_child(n, "model_id", text=model_id) 127 add_child(n, "stepping_id", text=hex(leaf_1.stepping)) 128 add_child(n, "core_type", text=core_type) 129 add_child(n, "native_model_id", text=native_model_id) 130 131 extract_model(processors_node, cpu_id, family_id, model_id, core_type, native_model_id) 132 else: 133 n.append(last_node) 134 135 if not created: 136 break 137 138 last_node = n 139 last_shift = leaf_topo.num_bit_shift 140 subleaf += 1 141 142def extract_hwp_info(processors_node): 143 if not processors_node.xpath("//capability[@id = 'hwp_supported']"): 144 return 145 146 # SDM Vol3 14.4.2: Additional MSRs associated with HWP may only be accessed after HWP is enabled 147 msr_hwp_en = MSR_IA32_PM_ENABLE() 148 msr_hwp_en.hwp_enable = 1 149 msr_hwp_en.wrmsr(0) 150 151 threads = processors_node.xpath("//thread") 152 for thread in threads: 153 cpu_id = get_node(thread, "cpu_id/text()") 154 msr_regs = [MSR_IA32_HWP_CAPABILITIES,] 155 for msr_reg in msr_regs: 156 msr_data = msr_reg.rdmsr(cpu_id) 157 for attr in msr_data.attribute_bits: 158 add_child(thread, attr, str(getattr(msr_data, attr))) 159 160def extract_psd_info(processors_node): 161 sysnode = '/sys/devices/system/cpu/' 162 threads = processors_node.xpath("//thread") 163 for thread in threads: 164 cpu_id = get_node(thread, "cpu_id/text()") 165 try: 166 with open(sysnode + "cpu{cpu_id}/cpufreq/freqdomain_cpus", 'r') as f_node: 167 freqdomain_cpus = f_node.read() 168 except IOError: 169 logging.info("No _PSD info for cpu {cpu_id}") 170 freqdomain_cpus = cpu_id 171 172 freqdomain_cpus.replace('\n','') 173 add_child(thread, "freqdomain_cpus", freqdomain_cpus) 174 175def extract(args, board_etree): 176 processors_node = get_node(board_etree, "//processors") 177 extract_topology(processors_node) 178 extract_hwp_info(processors_node) 179 extract_psd_info(processors_node) 180