mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-07-31 07:20:55 +00:00
board_inspector/cpuparser: add CPUID parsers
This patch adds a parser of CPU identification information reported by the CPUID instruction. The framework is based on the CPUID parsing facilities in BITS (https://biosbits.org/), but with the following changes. 1. The CPUID data is fetched by executing the `cpuid` utility, rather than executing the `cpuid` instruction. This avoids introducing any additional library or Python/C extension and gets a CPUID leaf on all physical cores in one shot. 2. Parsers of CPUID leaves 0x10, 0x1A and 0x1F are added. New fields in existing leaves are also added. 3. A wrapper function, named `parse_cpuid`, is added as the single API that allows other modules to get an arbitrary CPUID leaf or subleaf. Tracked-On: #5922 Signed-off-by: Junjie Mao <junjie.mao@intel.com>
This commit is contained in:
parent
05c738a480
commit
598be99dc2
61
misc/config_tools/board_inspector/cpuparser/__init__.py
Normal file
61
misc/config_tools/board_inspector/cpuparser/__init__.py
Normal file
@ -0,0 +1,61 @@
|
||||
# Copyright (C) 2021 Intel Corporation. All rights reserved.
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
#
|
||||
|
||||
import cpuparser.cpuids
|
||||
|
||||
dispatch_table = {
|
||||
0x0: cpuparser.cpuids.LEAF_0,
|
||||
0x1: cpuparser.cpuids.LEAF_1,
|
||||
0x2: cpuparser.cpuids.LEAF_2,
|
||||
0x4: cpuparser.cpuids.LEAF_4,
|
||||
0x5: cpuparser.cpuids.LEAF_5,
|
||||
0x6: cpuparser.cpuids.LEAF_6,
|
||||
0x7: cpuparser.cpuids.LEAF_7,
|
||||
0x9: cpuparser.cpuids.LEAF_9,
|
||||
0xA: cpuparser.cpuids.LEAF_A,
|
||||
0xB: cpuparser.cpuids.LEAF_B,
|
||||
# 0xD: multiple parsers
|
||||
# 0xF: multiple parsers
|
||||
# 0x10: multiple parsers
|
||||
0x1A: cpuparser.cpuids.LEAF_1A,
|
||||
0x1F: cpuparser.cpuids.LEAF_1F,
|
||||
0x80000000: cpuparser.cpuids.LEAF_80000000,
|
||||
0x80000001: cpuparser.cpuids.LEAF_80000001,
|
||||
0x80000002: cpuparser.cpuids.LEAF_80000002,
|
||||
0x80000003: cpuparser.cpuids.LEAF_80000003,
|
||||
0x80000004: cpuparser.cpuids.LEAF_80000004,
|
||||
0x80000006: cpuparser.cpuids.LEAF_80000006,
|
||||
0x80000007: cpuparser.cpuids.LEAF_80000007,
|
||||
0x80000008: cpuparser.cpuids.LEAF_80000008,
|
||||
}
|
||||
|
||||
def parse_cpuid(leaf, subleaf, cpu_id):
|
||||
if leaf in dispatch_table.keys():
|
||||
return dispatch_table[leaf].read(cpu_id, subleaf)
|
||||
elif leaf == 0xD:
|
||||
if subleaf == 0:
|
||||
return cpuparser.cpuids.LEAF_D.read(cpu_id, subleaf)
|
||||
elif subleaf == 1:
|
||||
return cpuparser.cpuids.LEAF_D_1.read(cpu_id, subleaf)
|
||||
else:
|
||||
return cpuparser.cpuids.LEAF_D_n.read(cpu_id, subleaf)
|
||||
elif leaf == 0xF:
|
||||
if subleaf == 0:
|
||||
return cpuparser.cpuids.LEAF_F.read(cpu_id, subleaf)
|
||||
elif subleaf == 1:
|
||||
return cpuparser.cpuids.LEAF_F_1.read(cpu_id, subleaf)
|
||||
else:
|
||||
return cpuparser.cpuids.LEAF_F_n.read(cpu_id, subleaf)
|
||||
elif leaf == 0x10:
|
||||
if subleaf == 0:
|
||||
return cpuparser.cpuids.LEAF_10.read(cpu_id, subleaf)
|
||||
elif subleaf == 1 or subleaf == 2:
|
||||
return cpuparser.cpuids.LEAF_10_1.read(cpu_id, subleaf)
|
||||
elif subleaf == 3:
|
||||
return cpuparser.cpuids.LEAF_10_3.read(cpu_id, subleaf)
|
||||
else:
|
||||
return None
|
||||
else:
|
||||
return None
|
752
misc/config_tools/board_inspector/cpuparser/cpuids.py
Normal file
752
misc/config_tools/board_inspector/cpuparser/cpuids.py
Normal file
@ -0,0 +1,752 @@
|
||||
# Copyright (C) 2021 Intel Corporation. All rights reserved.
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
#
|
||||
|
||||
"""CPUID register decoding."""
|
||||
|
||||
from cpuparser.platformbase import CPUID, cpuidfield
|
||||
import struct
|
||||
|
||||
EAX = 0
|
||||
EBX = 1
|
||||
ECX = 2
|
||||
EDX = 3
|
||||
|
||||
class LEAF_0(CPUID):
|
||||
"""Basic CPUID information including vendor and max supported basic leaf."""
|
||||
|
||||
leaf = 0x0
|
||||
max_leaf = cpuidfield(EAX, 31, 0, doc="Highest value the CPUID recognizes for returning basic processor information")
|
||||
|
||||
@property
|
||||
def vendor(self):
|
||||
"""Vendor identification string"""
|
||||
return struct.pack('III', self.regs.ebx, self.regs.edx, self.regs.ecx)
|
||||
|
||||
class LEAF_1(CPUID):
|
||||
"""Basic CPUID Information
|
||||
|
||||
Contains version type, family, model, and stepping ID; brand index; CLFLUSH
|
||||
line size; maximum number of addressable IDs for logical processors in the
|
||||
physical package; initial APIC ID; and feature information"""
|
||||
|
||||
leaf = 0x1
|
||||
|
||||
stepping = cpuidfield(EAX, 3, 0, doc="Stepping ID")
|
||||
model = cpuidfield(EAX, 7, 4, doc="Model")
|
||||
family = cpuidfield(EAX, 11, 8, doc="Family ID")
|
||||
processor_type = cpuidfield(EAX, 13, 12, doc="Processor Type")
|
||||
ext_model = cpuidfield(EAX, 19, 16, doc="Extended Model ID")
|
||||
ext_family = cpuidfield(EAX, 27, 20, doc="Extended Family ID")
|
||||
|
||||
brand_index = cpuidfield(EBX, 7, 0, doc="Brand index")
|
||||
CLFLUSH_line_size = cpuidfield(EBX, 15, 8, doc="CLFLUSH instruction cache line size (in 8-byte words)")
|
||||
max_logical_processor_ids = cpuidfield(EBX, 23, 16, doc="The maximum number of addressable IDs for logical processors in the physical package.")
|
||||
initial_apic_id = cpuidfield(EBX, 31, 24, doc="Initial APIC ID")
|
||||
|
||||
sse3 = cpuidfield(ECX, 0, 0)
|
||||
pclmulqdq = cpuidfield(ECX, 1, 1)
|
||||
dtes64 = cpuidfield(ECX, 2, 2)
|
||||
monitor = cpuidfield(ECX, 3, 3)
|
||||
ds_cpl = cpuidfield(ECX, 4, 4)
|
||||
vmx = cpuidfield(ECX, 5, 5)
|
||||
smx = cpuidfield(ECX, 6, 6)
|
||||
est = cpuidfield(ECX, 7, 7)
|
||||
tm2 = cpuidfield(ECX, 8, 8)
|
||||
ssse3 = cpuidfield(ECX, 9, 9)
|
||||
cnxt_id = cpuidfield(ECX, 10, 10)
|
||||
sdbg = cpuidfield(ECX, 11, 11)
|
||||
fma = cpuidfield(ECX, 12, 12)
|
||||
cmpxchg16b = cpuidfield(ECX, 13, 13)
|
||||
xtpr = cpuidfield(ECX, 14, 14)
|
||||
pdcm = cpuidfield(ECX, 15, 15)
|
||||
pcid = cpuidfield(ECX, 17, 17)
|
||||
dca = cpuidfield(ECX, 18, 18)
|
||||
sse4_1 = cpuidfield(ECX, 19, 19)
|
||||
sse4_2 = cpuidfield(ECX, 20, 20)
|
||||
x2apic = cpuidfield(ECX, 21, 21)
|
||||
movbe = cpuidfield(ECX, 22, 22)
|
||||
popcnt = cpuidfield(ECX, 23, 23)
|
||||
tsc_deadline = cpuidfield(ECX, 24, 24)
|
||||
aes = cpuidfield(ECX, 25, 25)
|
||||
xsave = cpuidfield(ECX, 26, 26)
|
||||
osxsave = cpuidfield(ECX, 27, 27)
|
||||
avx = cpuidfield(ECX, 28, 28)
|
||||
f16c = cpuidfield(ECX, 29, 29)
|
||||
rdrand = cpuidfield(ECX, 30, 30)
|
||||
|
||||
fpu = cpuidfield(EDX, 0, 0)
|
||||
vme = cpuidfield(EDX, 1, 1)
|
||||
de = cpuidfield(EDX, 2, 2)
|
||||
pse = cpuidfield(EDX, 3, 3)
|
||||
tsc = cpuidfield(EDX, 4, 4)
|
||||
msr = cpuidfield(EDX, 5, 5)
|
||||
pae = cpuidfield(EDX, 6, 6)
|
||||
mce = cpuidfield(EDX, 7, 7)
|
||||
cx8 = cpuidfield(EDX, 8, 8)
|
||||
apic = cpuidfield(EDX, 9, 9)
|
||||
sep = cpuidfield(EDX, 11, 11)
|
||||
mtrr = cpuidfield(EDX, 12, 12)
|
||||
pge = cpuidfield(EDX, 13, 13)
|
||||
mca = cpuidfield(EDX, 14, 14)
|
||||
cmov = cpuidfield(EDX, 15, 15)
|
||||
pat = cpuidfield(EDX, 16, 16)
|
||||
pse36 = cpuidfield(EDX, 17, 17)
|
||||
psn = cpuidfield(EDX, 18, 18)
|
||||
clfsh = cpuidfield(EDX, 19, 19)
|
||||
ds = cpuidfield(EDX, 21, 21)
|
||||
acpi = cpuidfield(EDX, 22, 22)
|
||||
mmx = cpuidfield(EDX, 23, 23)
|
||||
fxsr = cpuidfield(EDX, 24, 24)
|
||||
sse = cpuidfield(EDX, 25, 25)
|
||||
sse2 = cpuidfield(EDX, 26, 26)
|
||||
ss = cpuidfield(EDX, 27, 27)
|
||||
htt = cpuidfield(EDX, 28, 28)
|
||||
tm = cpuidfield(EDX, 29, 29)
|
||||
pbe = cpuidfield(EDX, 31, 31)
|
||||
|
||||
@property
|
||||
def display_family(self):
|
||||
if self.family == 0xf:
|
||||
return self.ext_family + self.family
|
||||
return self.family
|
||||
|
||||
@property
|
||||
def display_model(self):
|
||||
if self.family == 0xf or self.family == 0x6:
|
||||
return (self.ext_model << 4) + self.model
|
||||
return self.model
|
||||
|
||||
capability_bits = [
|
||||
"sse3",
|
||||
"pclmulqdq",
|
||||
"dtes64",
|
||||
"monitor",
|
||||
"ds_cpl",
|
||||
"vmx",
|
||||
"smx",
|
||||
"est",
|
||||
"tm2",
|
||||
"ssse3",
|
||||
"cnxt_id",
|
||||
"sdbg",
|
||||
"fma",
|
||||
"cmpxchg16b",
|
||||
"xtpr",
|
||||
"pdcm",
|
||||
"pcid",
|
||||
"dca",
|
||||
"sse4_1",
|
||||
"sse4_2",
|
||||
"x2apic",
|
||||
"movbe",
|
||||
"popcnt",
|
||||
"tsc_deadline",
|
||||
"aes",
|
||||
"xsave",
|
||||
"avx",
|
||||
"f16c",
|
||||
"rdrand",
|
||||
"fpu",
|
||||
"vme",
|
||||
"de",
|
||||
"pse",
|
||||
"tsc",
|
||||
"msr",
|
||||
"pae",
|
||||
"mce",
|
||||
"cx8",
|
||||
"apic",
|
||||
"sep",
|
||||
"mtrr",
|
||||
"pge",
|
||||
"mca",
|
||||
"cmov",
|
||||
"pat",
|
||||
"pse36",
|
||||
"psn",
|
||||
"clfsh",
|
||||
"ds",
|
||||
"acpi",
|
||||
"mmx",
|
||||
"fxsr",
|
||||
"sse",
|
||||
"sse2",
|
||||
"ss",
|
||||
"htt",
|
||||
"tm",
|
||||
"pbe",
|
||||
]
|
||||
|
||||
class LEAF_2(CPUID):
|
||||
"""TLB, Cache, and Prefetch Information"""
|
||||
|
||||
leaf = 0x2
|
||||
times_to_run = cpuidfield(EAX, 7, 0, doc="Number of times CPUID must be executed with EAX = 2 to retrieve a complete description of the processor's TLB, Cache, and Prefetch hardware")
|
||||
|
||||
class LEAF_4(CPUID):
|
||||
"""Deterministic cache parameters
|
||||
|
||||
Returns encoded data that describes a set of deterministic cache parameters
|
||||
for the cache level associated in ECX"""
|
||||
|
||||
leaf = 0x4
|
||||
cache_type = cpuidfield(EAX, 4, 0, doc="Cache Type Field")
|
||||
cache_level = cpuidfield(EAX, 7, 5, doc="Cache Level")
|
||||
self_initializing = cpuidfield(EAX, 8, 8, doc="Self Initializing Cache Level")
|
||||
fully_associative = cpuidfield(EAX, 9, 9, doc="Fully Associative Cache")
|
||||
max_logical_processors_sharing_cache_z = cpuidfield(EAX, 25, 14, doc="Max number of addressable IDs for logical processors sharing this cache (zero based)")
|
||||
max_cores_sharing_cache_z = cpuidfield(EAX, 31, 26, doc="Max number of addressable IDs for processor cores in the physical package (zero based)")
|
||||
|
||||
line_size_z = cpuidfield(EBX, 11, 0, doc="System Coherency Line Size (zero-based)")
|
||||
partitions_z = cpuidfield(EBX, 21, 12, doc="Physical Line Partitions (zero-based)")
|
||||
ways_z = cpuidfield(EBX, 31, 22, doc="Ways of associativity (zero-based)")
|
||||
|
||||
sets_z = cpuidfield(ECX, 31, 0, doc="Sets (zero-based)")
|
||||
|
||||
write_back_invalidate = cpuidfield(EDX, 0, 0, doc="Write-back Invalidate/Invalidate")
|
||||
cache_inclusiveness = cpuidfield(EDX, 1, 1, doc="Cache Inclusiveness")
|
||||
complex_cache_indexing = cpuidfield(EDX, 2, 2, doc="Complex Cache indexing")
|
||||
|
||||
@property
|
||||
def max_logical_processors_sharing_cache(self):
|
||||
"""Maximum number of addressable IDs for logical processors sharing this cache"""
|
||||
return self.max_logical_processors_sharing_cache_z + 1
|
||||
|
||||
@property
|
||||
def max_cores_sharing_cache(self):
|
||||
"""Maximum number of addressable IDs for processor cores in the physical pacakge"""
|
||||
return self.max_cores_sharing_cache_z + 1
|
||||
|
||||
@property
|
||||
def partitions(self):
|
||||
"""Number of physical line partitions"""
|
||||
return self.partitions_z + 1
|
||||
|
||||
@property
|
||||
def line_size(self):
|
||||
"""System Coherency line size"""
|
||||
return self.line_size_z + 1
|
||||
|
||||
@property
|
||||
def ways(self):
|
||||
"""Ways of associativity"""
|
||||
return self.ways_z + 1
|
||||
|
||||
@property
|
||||
def sets(self):
|
||||
"""Number of sets"""
|
||||
return self.sets_z + 1
|
||||
|
||||
@property
|
||||
def cache_size(self):
|
||||
"""Cache size in bytes"""
|
||||
return self.ways * self.partitions * self.line_size * self.sets
|
||||
|
||||
class LEAF_5(CPUID):
|
||||
"""MONITOR/MWAIT Leaf
|
||||
|
||||
Returns information about features available to MONITOR/MWAIT instructions"""
|
||||
|
||||
leaf = 0x5
|
||||
|
||||
smallest_monitor_line_size = cpuidfield(EAX, 15, 0, doc="Smallest monitor-line size in bytes")
|
||||
|
||||
largest_monitor_line_size = cpuidfield(EBX, 15, 0, doc="Largest monitor-line size in bytes")
|
||||
|
||||
monitor_mwait_supported = cpuidfield(ECX, 0, 0, doc="Enumeration of MONITOR/MWAIT extensions supported")
|
||||
interrupt_break_event_supported = cpuidfield(ECX, 1, 1, doc="Supports treating interrupts as break-events for MWAIT, even when interrupts disabled")
|
||||
|
||||
c0 = cpuidfield(EDX, 3, 0, doc="Number of C0 sub C-states supported using MWAIT")
|
||||
c1 = cpuidfield(EDX, 7, 4, doc="Number of C1 sub C-states supported using MWAIT")
|
||||
c2 = cpuidfield(EDX, 11, 8, doc="Number of C2 sub C-states supported using MWAIT")
|
||||
c3 = cpuidfield(EDX, 15, 12, doc="Number of C3 sub C-states supported using MWAIT")
|
||||
c4 = cpuidfield(EDX, 19, 16, doc="Number of C4 sub C-states supported using MWAIT")
|
||||
|
||||
class LEAF_6(CPUID):
|
||||
"""Thermal and Power Management leaf
|
||||
|
||||
Returns information about the maximum input values for sub-leaves that contain extended feature flags."""
|
||||
|
||||
leaf = 0x6
|
||||
|
||||
digital_temperature_sensor_supported = cpuidfield(EAX, 0, 0, doc = "Digital temperature sensor is supported if set")
|
||||
turbo_boost_available = cpuidfield(EAX, 1, 1, doc = "Intel Turbo Boost technology available")
|
||||
arat_supported = cpuidfield(EAX, 2, 2, doc = "APIC-Timer-always-running feature is supported if set")
|
||||
pln_supported = cpuidfield(EAX, 4, 4, doc = "Power limit notification controls are supported if set")
|
||||
ecmd_supported = cpuidfield(EAX, 5, 5, doc = "Clock modulation duty cycle extension is supported if set")
|
||||
package_thermal_management_supported = cpuidfield(EAX, 6, 6, doc = "Package thermal management is supported if set")
|
||||
|
||||
num_interrupt_thresholds = cpuidfield(EBX, 3, 0, doc="Number of interrupt thresholds in digital thermal sensor")
|
||||
|
||||
hardware_coordination_feedback_capability = cpuidfield(ECX, 0, 0, doc="Hardware coordination feedback capability")
|
||||
performance_energy_bias = cpuidfield(ECX, 3, 3, doc="Performance-energy bias preference support")
|
||||
|
||||
class LEAF_7(CPUID):
|
||||
"""Structured Extended Feature Flags Enumeration Leaf
|
||||
|
||||
Returns information about the maximum input value for sub-leaves that contain
|
||||
extended feature flags"""
|
||||
|
||||
leaf = 0x7
|
||||
|
||||
max_input_values = cpuidfield(EAX, 31, 0, doc="Reports the maximum input value for supported leaf 7 sub-leaves")
|
||||
|
||||
fsgsbase = cpuidfield(EBX, 0, 0, doc="Supports RDFSBASE/RDGSBASE/WRFSBASE/WRGSBASE if 1")
|
||||
ia32_tsc_adjust_msr = cpuidfield(EBX, 1, 1, doc="IA32_TSC_ADJUST MSR is supported if 1")
|
||||
sgx = cpuidfield(EBX, 2, 2, doc="Supports Intel® Software Guard Extensions (Intel® SGX Extensions) if 1")
|
||||
bmi1 = cpuidfield(EBX, 3, 3)
|
||||
hle = cpuidfield(EBX, 4, 4)
|
||||
avx2 = cpuidfield(EBX, 5, 5)
|
||||
fdp_excptn_only = cpuidfield(EBX, 6, 6, doc="x87 FPU Data Pointer updated only on x87 exceptions if 1")
|
||||
smep = cpuidfield(EBX, 7, 7, doc="Supports Supervisor Mode Execution Protection if 1")
|
||||
bmi2 = cpuidfield(EBX, 8, 8)
|
||||
erms = cpuidfield(EBX, 9, 9, doc="Supports Enhanced REP MOVSB/STOSB if 1")
|
||||
invpcid = cpuidfield(EBX, 10, 10, doc="Supports INVPCID instruction for system software that manages process-context identifiers if 1")
|
||||
rtm = cpuidfield(EBX, 11, 11)
|
||||
qm = cpuidfield(EBX, 12, 12, doc="Supports Quality of Service Monitoring capability if 1")
|
||||
deprecate_fpu = cpuidfield(EBX, 13, 13, doc="Deprecates FPS CS and FPU DS values if 1")
|
||||
mpx = cpuidfield(EBX, 14, 14, doc="Supports Intel® Memory Protection Extensions if 1")
|
||||
rdt_a = cpuidfield(EBX, 15, 15, doc="Supports Intel® Resource Director Technology (Intel® RDT) Allocation capability if 1")
|
||||
avx512f = cpuidfield(EBX, 16, 16)
|
||||
avx512dq = cpuidfield(EBX, 17, 17)
|
||||
rdseed = cpuidfield(EBX, 18, 18)
|
||||
adx = cpuidfield(EBX, 19, 19)
|
||||
smap = cpuidfield(EBX, 20, 20, doc="Supports Supervisor-Mode Access Prevention (and the CLAC/STAC instructions) if 1")
|
||||
avx512_ifma = cpuidfield(EBX, 21, 21)
|
||||
clflushopt = cpuidfield(EBX, 23, 23)
|
||||
clwb = cpuidfield(EBX, 24, 24)
|
||||
intel_pt = cpuidfield(EBX, 25, 25)
|
||||
avx512pf = cpuidfield(EBX, 26, 26)
|
||||
avx512er = cpuidfield(EBX, 27, 27)
|
||||
avx512cd = cpuidfield(EBX, 28, 28)
|
||||
sha = cpuidfield(EBX, 29, 29, doc="Supports Intel® Secure Hash Algorithm Extensions (Intel® SHA Extensions) if 1")
|
||||
avx512bw = cpuidfield(EBX, 30, 30)
|
||||
avx512vl = cpuidfield(EBX, 31, 31)
|
||||
|
||||
prefetchwt1 = cpuidfield(ECX, 0, 0)
|
||||
avx512_vbmi = cpuidfield(ECX, 1, 1)
|
||||
umip = cpuidfield(ECX, 2, 2, doc="Supports user-mode instruction prevention if 1")
|
||||
pku = cpuidfield(ECX, 3, 3, doc="Supports protection keys for user-mode pages if 1")
|
||||
ospke = cpuidfield(ECX, 4, 4, doc="If 1, OS has set CR4.PKE to enable protection keys (and the RDPKRU/WRPKRU instructions)")
|
||||
waitpkg = cpuidfield(ECX, 5, 5)
|
||||
avx512_vbmi2 = cpuidfield(ECX, 6, 6)
|
||||
cet_ss = cpuidfield(ECX, 7, 7, doc="Supports CET shadow stack features if 1")
|
||||
gfni = cpuidfield(ECX, 8, 8)
|
||||
vaes = cpuidfield(ECX, 9, 9)
|
||||
vpclmulqdq = cpuidfield(ECX, 10, 10)
|
||||
avx512_vnni = cpuidfield(ECX, 11, 11)
|
||||
avx512_bitalg = cpuidfield(ECX, 12, 12)
|
||||
tme_en = cpuidfield(ECX, 13, 13)
|
||||
avx512_vpopcntdq = cpuidfield(ECX, 14, 14)
|
||||
la57 = cpuidfield(ECX, 16, 16, doc="Supports 57-bit linear addresses and five-level paging if 1")
|
||||
mawau = cpuidfield(ECX, 21, 17, doc="The value of MAWAU used by the BNDLDX and BNDSTX instructions in 64-bit mode")
|
||||
rdpid = cpuidfield(ECX, 22, 22, doc="RDPID and IA32_TSC_AUX are available if 1")
|
||||
kl = cpuidfield(ECX, 23, 23, doc="Supports Key Locker if 1")
|
||||
cldemote = cpuidfield(ECX, 25, 25, doc="Supports cache line demote if 1")
|
||||
movdiri = cpuidfield(ECX, 27, 27, doc="Supports MOVDIRI if 1")
|
||||
movdiri64b = cpuidfield(ECX, 28, 28, doc="Supports MOVDIRI64B if 1")
|
||||
sgx_lc = cpuidfield(ECX, 30, 30, doc="Supports SGX Launch Configuration if 1")
|
||||
pks = cpuidfield(ECX, 31, 31, doc="Supports protection keys for supervisor-mode pages if 1")
|
||||
|
||||
avx512_4vnniw = cpuidfield(EDX, 2, 2)
|
||||
avx512_4fmaps = cpuidfield(EDX, 3, 3)
|
||||
fast_short_rep_mov = cpuidfield(EDX, 4, 4)
|
||||
avx512_vp2intersect = cpuidfield(EDX, 8, 8)
|
||||
md_clear = cpuidfield(EDX, 10, 10)
|
||||
hybrid = cpuidfield(EDX, 15, 15, doc="If 1, the processor is identified as a hybrid part")
|
||||
pconfig = cpuidfield(EDX, 18, 18, doc="Supports PCONFIG if 1")
|
||||
cet_ibt = cpuidfield(EDX, 20, 20, doc="Supports CET indirect branch tracking features if 1")
|
||||
ibrs_ibpb = cpuidfield(EDX, 26, 26, doc="Enumerates support for indirect branch restricted speculation (IBRS) and the indirect branch predictor barrier (IBPB)")
|
||||
stibp = cpuidfield(EDX, 27, 27, doc="Enumerates support for single thread indirect branch predictors (STIBP)")
|
||||
l1d_flush = cpuidfield(EDX, 28, 28, doc="Enumerates support for L1D_FLUSH")
|
||||
ia32_arch_capabilities = cpuidfield(EDX, 29, 29, doc="Enumerates support for the IA32_ARCH_CAPABILITIES MSR")
|
||||
ia32_core_capabilities = cpuidfield(EDX, 30, 30, doc="Enumerates support for the IA32_CORE_CAPABILITIES MSR")
|
||||
ssbd = cpuidfield(EDX, 31, 31, doc="Enumerates support for Speculative Store Bypass Disable (SSBD)")
|
||||
|
||||
capability_bits = [
|
||||
"fsgsbase",
|
||||
"ia32_tsc_adjust_msr",
|
||||
"sgx",
|
||||
"bmi1",
|
||||
"hle",
|
||||
"avx2",
|
||||
"fdp_excptn_only",
|
||||
"smep",
|
||||
"bmi2",
|
||||
"erms",
|
||||
"invpcid",
|
||||
"rtm",
|
||||
"qm",
|
||||
"deprecate_fpu",
|
||||
"mpx",
|
||||
"rdt_a",
|
||||
"avx512f",
|
||||
"avx512dq",
|
||||
"rdseed",
|
||||
"adx",
|
||||
"smap",
|
||||
"avx512_ifma",
|
||||
"clflushopt",
|
||||
"clwb",
|
||||
"intel_pt",
|
||||
"avx512pf",
|
||||
"avx512er",
|
||||
"avx512cd",
|
||||
"sha",
|
||||
"avx512bw",
|
||||
"avx512vl",
|
||||
"prefetchwt1",
|
||||
"avx512_vbmi",
|
||||
"umip",
|
||||
"pku",
|
||||
"waitpkg",
|
||||
"avx512_vbmi2",
|
||||
"cet_ss",
|
||||
"gfni",
|
||||
"vaes",
|
||||
"vpclmulqdq",
|
||||
"avx512_vnni",
|
||||
"avx512_bitalg",
|
||||
"tme_en",
|
||||
"avx512_vpopcntdq",
|
||||
"la57",
|
||||
"mawau",
|
||||
"rdpid",
|
||||
"kl",
|
||||
"cldemote",
|
||||
"movdiri",
|
||||
"movdiri64b",
|
||||
"sgx_lc",
|
||||
"pks",
|
||||
"avx512_4vnniw",
|
||||
"avx512_4fmaps",
|
||||
"fast_short_rep_mov",
|
||||
"avx512_vp2intersect",
|
||||
"md_clear",
|
||||
"hybrid",
|
||||
"pconfig",
|
||||
"cet_ibt",
|
||||
"ibrs_ibpb",
|
||||
"stibp",
|
||||
"l1d_flush",
|
||||
"ia32_arch_capabilities",
|
||||
"ia32_core_capabilities",
|
||||
"ssbd",
|
||||
]
|
||||
|
||||
class LEAF_9(CPUID):
|
||||
"""Direct Cache Access Information leaf
|
||||
|
||||
Returns information about Direct Cache Access capabilities"""
|
||||
|
||||
leaf = 0x9
|
||||
|
||||
platform_dca_cap = cpuidfield(EAX, 31, 0, doc="Value of bits of IA32_PLATFORM_DCA_CAP MSR (address 1F8H)")
|
||||
|
||||
class LEAF_A(CPUID):
|
||||
"""Architectural Performance Monitoring Leaf
|
||||
|
||||
Returns information about support for architectural performance monitoring capabilities"""
|
||||
|
||||
leaf = 0xA
|
||||
|
||||
architectural_performance_monitor_version_id = cpuidfield(EAX, 7, 0, doc="Version ID of architectural performance monitoring")
|
||||
gp_performance_monitor_counters = cpuidfield(EAX, 15, 8, doc="Number of general-purpose performance monitoring counter per logical processor")
|
||||
gp_performance_counter_width = cpuidfield(EAX, 23, 16, doc="Bit width of general-purpose, performance monitoring counter")
|
||||
ebx_bit_vector_length = cpuidfield(EAX, 31, 24, doc="Length of EBX bit vector to enumerate architectural performance monitoring events")
|
||||
|
||||
core_cycle_event = cpuidfield(EBX, 0, 0, doc="Core cycle event not available if 1")
|
||||
instruction_retired_event = cpuidfield(EBX, 1, 1, doc="Instruction retired event not available if 1")
|
||||
reference_cycles_event = cpuidfield(EBX, 2, 2, doc="Reference cycles event not available if 1")
|
||||
llc_ref_event = cpuidfield(EBX, 3, 3, doc="Last-level cache reference event not available if 1")
|
||||
llc_misses_event = cpuidfield(EBX, 4, 4, doc= "Last-level cache misses event not available if 1")
|
||||
branch_instruction_retired_event = cpuidfield(EBX, 5, 5, doc="Branch instruction retired event not available if 1")
|
||||
branch_mispredict_retired_event = cpuidfield(EBX, 6, 6, doc="Branch mispredict retired event not available if 1")
|
||||
|
||||
ff_performance_counters = cpuidfield(EDX, 4, 0, doc="Number of fixed-function performance counters")
|
||||
ff_performance_counter_width = cpuidfield(EDX, 12, 5, doc="Bit width of fixed-function performance counters")
|
||||
|
||||
class LEAF_B(CPUID):
|
||||
"""Extended Topology Enumeration Leaf
|
||||
|
||||
Returns information about extended topology enumeration data"""
|
||||
|
||||
leaf = 0xB
|
||||
|
||||
num_bit_shift = cpuidfield(EAX, 4, 0, doc="Number of bits to shift right on x2APID ID to get a unique topology ID of the next level type")
|
||||
|
||||
logical_proccessors_at_level = cpuidfield(EBX, 15, 0, doc="Number of logical processors at this level type.")
|
||||
|
||||
level_number = cpuidfield(ECX, 7, 0, doc="Level number")
|
||||
level_type = cpuidfield(ECX, 15, 8, doc="Level type")
|
||||
|
||||
x2apic_id = cpuidfield(EDX, 31, 0, doc="x2APIC ID of the current logical processor")
|
||||
|
||||
class LEAF_D(CPUID):
|
||||
"""Processor Extended State Enumeration Main Leaf and Sub-Leaves.
|
||||
|
||||
Returns information about the bit-vector representation of all processor
|
||||
state extensions that are supported in the processor, and storage size
|
||||
requirements of the XSAVE/XRSTOR area. Output depends on initial value of ECX."""
|
||||
|
||||
leaf = 0xD
|
||||
|
||||
valid_bits_xcr0_lower = cpuidfield(EAX, 31, 0, doc="Reports the valid bit fields of the lower 32 bits of XCR0. If a bit is 0, the corresponding bit field in XCR0 is reserved")
|
||||
|
||||
legacy_x87 = cpuidfield(EAX, 0, 0, doc="legacy x87")
|
||||
sse_128_bit = cpuidfield(EAX, 1, 1, doc="128-bit SSE")
|
||||
avx_256_bit = cpuidfield(EAX, 2, 2, doc="256-bit AVX")
|
||||
|
||||
max_size_enabled_xcr0 = cpuidfield(EBX, 31, 0, doc="Maximum size (bytes, from the beginning of the XSAVE/XRSTOR save area) required by enabled features in XCR0. May be different than ECX if some features at the end of the XSAVE save area are not enabled.")
|
||||
|
||||
max_size_supported_xcr0 = cpuidfield(ECX, 31, 0, doc="Maximum size (bytes, from the beginning of the XSAVE/XRSTOR save area) of the XSAVE/XRSTOR save area required by all supported features in the processor, i.e all the valid bit fields in XCR0.")
|
||||
|
||||
valid_bits_xcr0_upper = cpuidfield(EDX, 31, 0, doc="The valid bit fields of the upper 32 bits of XCR0. If a bit is 0, the corresponding bit field in XCR0 is reserved.")
|
||||
|
||||
def __getitem__(self, subleaf):
|
||||
if subleaf == 0:
|
||||
return self.read(self.cpu_id, subleaf)
|
||||
elif subleaf == 1:
|
||||
return LEAF_D_1.read(self.cpu_id, subleaf)
|
||||
return LEAF_D_n.read(self.cpu_id, subleaf)
|
||||
|
||||
class LEAF_D_1(CPUID):
|
||||
"""Processor Extended State Enumeration Main Leaf and Sub-Leaves.
|
||||
|
||||
Returns information about the bit-vector representation of all processor
|
||||
state extensions that are supported in the processor, and storage size
|
||||
requirements of the XSAVE/XRSTOR area. Output depends on initial value of ECX."""
|
||||
|
||||
leaf = 0xD
|
||||
|
||||
xsaveopt = cpuidfield(EAX, 0, 0, doc="XSAVEOPT is available")
|
||||
|
||||
class LEAF_D_n(CPUID):
|
||||
"""Processor Extended State Enumeration Main Leaf and Sub-Leaves.
|
||||
|
||||
Returns information about the bit-vector representation of all processor
|
||||
state extensions that are supported in the processor, and storage size
|
||||
requirements of the XSAVE/XRSTOR area. Output depends on initial value of ECX."""
|
||||
|
||||
leaf = 0xD
|
||||
|
||||
size = cpuidfield(EAX, 31, 0, doc="The size in bytes (from the offset specified in EBX) of the save area for an extended state feature associated with a valid sub-leaf index")
|
||||
|
||||
offset = cpuidfield(EBX, 31, 0, doc="The offset in bytes of this extended state component's save area from the beginning of the XSAVE/XRSTOR area.")
|
||||
|
||||
class LEAF_F(CPUID):
|
||||
"""Quality of Service Resource Type Enumeration Sub-Leaf and L3 Cache QoS Capability Enumeration Sub-leaf. Depends on value of ECX
|
||||
|
||||
Returns Quality of Service (QoS) Enumeration Information."""
|
||||
|
||||
leaf = 0xF
|
||||
|
||||
def __getitem__(self, subleaf):
|
||||
if subleaf == 0:
|
||||
return self.read(self.cpu_id, subleaf)
|
||||
elif subleaf == 1:
|
||||
return LEAF_F_1.read(self.cpu_id, subleaf)
|
||||
return LEAF_F_n.read(self.cpu_id, subleaf)
|
||||
|
||||
max_range_rmid_z = cpuidfield(EBX, 31, 0, doc="Maximum range (zero-based) of RMID within this physical processor of all types.")
|
||||
|
||||
l3_cache_qos = cpuidfield(EDX, 1, 1, doc="Supports L3 Cache QoS if 1")
|
||||
|
||||
@property
|
||||
def max_range_rmid(self):
|
||||
"""Maximum range of RMID within this physical processor of all types."""
|
||||
return self.max_range_rmid_z + 1
|
||||
|
||||
class LEAF_F_1(CPUID):
|
||||
"""Quality of Service Resource Type Enumeration Sub-Leaf and L3 Cache QoS Capability Enumeration Sub-leaf. Depends on value of ECX
|
||||
|
||||
Returns L3 Cache QoS Capability Enumeration Information."""
|
||||
|
||||
leaf = 0xF
|
||||
|
||||
qm_ctr_conversion_factor = cpuidfield(EBX, 31, 0, doc="Conversion factor from reported IA32_QM_CTR value to occupancy metric (bytes).")
|
||||
|
||||
l3_occupancy_monitoring = cpuidfield(EDX, 0, 0, doc="Supports L3 occupancy monitoring if 1")
|
||||
|
||||
max_range_rmid_z = cpuidfield(ECX, 31, 0, doc="Maximum range (zero-based) of RMID of this resource type")
|
||||
|
||||
@property
|
||||
def max_range_rmid(self):
|
||||
"""Maximum range of RMID of this resource type"""
|
||||
return self.max_range_rmid_z + 1
|
||||
|
||||
class LEAF_F_n(CPUID):
|
||||
"""Quality of Service Resource Type Enumeration Sub-Leaf and L3 Cache QoS Capability Enumeration Sub-leaf. Depends on value of ECX
|
||||
|
||||
Returns Quality of Service (QoS) Enumeration Information."""
|
||||
|
||||
leaf = 0xF
|
||||
|
||||
class LEAF_10(CPUID):
|
||||
"""Intel Resource Director Technology (Intel RDT) Allocation Enumeration Sub-leaf"""
|
||||
|
||||
leaf = 0x10
|
||||
|
||||
l3_cache_allocation = cpuidfield(EBX, 1, 1, doc="Supports L3 Cache Allocation Technology if 1.")
|
||||
l2_cache_allocation = cpuidfield(EBX, 2, 2, doc="Supports L2 Cache Allocation Technology if 1.")
|
||||
memory_bandwidth_allocation = cpuidfield(EBX, 3, 3, doc="Supports Memory Bandwidth Allocation if 1.")
|
||||
|
||||
class LEAF_10_1(CPUID):
|
||||
"""L3/L2 Cache Allocation Technology Enumeration Sub-leaf"""
|
||||
|
||||
leaf = 0x10
|
||||
|
||||
capacity_mask_length_z = cpuidfield(EAX, 4, 0, doc="Length of the capacity bit mask for the corresponding ResID (zero based).")
|
||||
isolation_map = cpuidfield(EBX, 31, 0, doc="Bit-granular map of isolation/contention of allocation units.")
|
||||
code_and_data_prioritization = cpuidfield(ECX, 2, 2, doc="Code and Data Prioritization Technology supported if 1.")
|
||||
clos_number_z = cpuidfield(EDX, 15, 0, doc="Highest COS number supported for this ResID.")
|
||||
|
||||
@property
|
||||
def capacity_mask_length(self):
|
||||
return self.capacity_mask_length_z + 1
|
||||
|
||||
@property
|
||||
def clos_number(self):
|
||||
return self.clos_number_z + 1
|
||||
|
||||
class LEAF_10_3(CPUID):
|
||||
"""Memory Bandwidth Allocation Enumeration Sub-leaf"""
|
||||
|
||||
leaf = 0x10
|
||||
|
||||
max_throttling_value_z = cpuidfield(EAX, 11, 0, doc="Reports the maximum MBA throttling value supported for the corresponding ResID (zero based).")
|
||||
linear_response_delay = cpuidfield(ECX, 2, 2, doc="Reports whether the response of the delay values is linear.")
|
||||
clos_number_z = cpuidfield(EDX, 15, 0, doc="Highest COS number supported for this ResID.")
|
||||
|
||||
@property
|
||||
def max_throttling_value(self):
|
||||
return self.max_throttling_value_z + 1
|
||||
|
||||
@property
|
||||
def clos_number(self):
|
||||
return self.clos_number_z + 1
|
||||
|
||||
class LEAF_1A(CPUID):
|
||||
"""Hybrid Information Enumeration Leaf"""
|
||||
|
||||
leaf = 0x1A
|
||||
|
||||
core_type_id = cpuidfield(EAX, 31, 24, doc="Core type")
|
||||
native_model_id = cpuidfield(EAX, 23, 0, doc="Native model ID")
|
||||
|
||||
core_types = {
|
||||
0x20: "Atom",
|
||||
0x40: "Core",
|
||||
}
|
||||
|
||||
@property
|
||||
def core_type(self):
|
||||
if self.core_type_id in self.core_types:
|
||||
return self.core_types[self.core_type_id]
|
||||
return "Reserved"
|
||||
|
||||
class LEAF_1F(LEAF_B):
|
||||
"""Extened Topology Enumeration Leaf v2"""
|
||||
|
||||
leaf = 0x1F
|
||||
|
||||
class LEAF_80000000(CPUID):
|
||||
"""Extended Function CPUID Information"""
|
||||
|
||||
leaf = 0x80000000
|
||||
|
||||
max_extended_leaf = cpuidfield(EAX, 31, 0, doc="Highest extended function input value understood by CPUID")
|
||||
|
||||
class LEAF_80000001(CPUID):
|
||||
"""Extended Function CPUID Information"""
|
||||
|
||||
leaf = 0x80000001
|
||||
|
||||
ext_signature_feature_bits = cpuidfield(EAX, 31, 0, doc="Extended processor signature and feature bits")
|
||||
|
||||
lahf_sahf_64 = cpuidfield(ECX, 0, 0, doc="LAHF/SAHF available in 64-bit mode")
|
||||
lzcnt = cpuidfield(ECX, 5, 5)
|
||||
prefetchw = cpuidfield(ECX, 8, 8)
|
||||
|
||||
syscall_sysret_64 = cpuidfield(EDX, 11, 11, doc="SYSCALL/SYSRET available in 64-bit mode")
|
||||
execute_disable = cpuidfield(EDX, 20, 20, doc="Execute Disable Bit available")
|
||||
gbyte_pages = cpuidfield(EDX, 26, 26, doc="GByte pages are available if 1")
|
||||
rdtscp_ia32_tsc_aux = cpuidfield(EDX, 27, 27, doc="RDTSCP and IA32_TSC_AUX are available if 1")
|
||||
intel_64 = cpuidfield(EDX, 29, 29, doc="Intel(R) 64 Architecture available if 1")
|
||||
|
||||
capability_bits = [
|
||||
"lahf_sahf_64",
|
||||
"lzcnt",
|
||||
"prefetchw",
|
||||
"syscall_sysret_64",
|
||||
"execute_disable",
|
||||
"gbyte_pages",
|
||||
"rdtscp_ia32_tsc_aux",
|
||||
"intel_64",
|
||||
]
|
||||
|
||||
class LEAF_80000002(CPUID):
|
||||
"""Extended Function CPUID Information
|
||||
|
||||
Processor Brand String"""
|
||||
|
||||
leaf = 0x80000002
|
||||
|
||||
@property
|
||||
def brandstring(self):
|
||||
"""Processor Brand String"""
|
||||
return struct.pack('IIII', self.regs.eax, self.regs.ebx, self.regs.ecx, self.regs.edx).rstrip(b"\x00")
|
||||
|
||||
class LEAF_80000003(CPUID):
|
||||
"""Extended Function CPUID Information
|
||||
|
||||
Processor Brand String Continued"""
|
||||
|
||||
leaf = 0x80000003
|
||||
|
||||
@property
|
||||
def brandstring(self):
|
||||
"""Processor Brand String"""
|
||||
return struct.pack('IIII', self.regs.eax, self.regs.ebx, self.regs.ecx, self.regs.edx).rstrip(b"\x00")
|
||||
|
||||
class LEAF_80000004(CPUID):
|
||||
"""Extended Function CPUID Information
|
||||
|
||||
Processor Brand String Continued"""
|
||||
|
||||
leaf = 0x80000004
|
||||
|
||||
@property
|
||||
def brandstring(self):
|
||||
"""Processor Brand String"""
|
||||
return struct.pack('IIII', self.regs.eax, self.regs.ebx, self.regs.ecx, self.regs.edx).rstrip(b"\x00")
|
||||
|
||||
class LEAF_80000006(CPUID):
|
||||
"""Extended Function CPUID Information"""
|
||||
|
||||
leaf = 0x80000006
|
||||
|
||||
cache_line_size = cpuidfield(ECX, 7, 0, doc="Cache Line size in bytes")
|
||||
|
||||
l2_associativity = cpuidfield(ECX, 15, 12, doc="L2 Associativity field")
|
||||
cache_size_k = cpuidfield(ECX, 31, 16, doc="Cache size in 1K units")
|
||||
|
||||
class LEAF_80000007(CPUID):
|
||||
"""Misc Feature Flags"""
|
||||
|
||||
leaf = 0x80000007
|
||||
|
||||
invariant_tsc = cpuidfield(EDX, 8, 8, doc="Invariant TSC available if 1")
|
||||
|
||||
capability_bits = [
|
||||
"invariant_tsc",
|
||||
]
|
||||
|
||||
class LEAF_80000008(CPUID):
|
||||
"""Returns linear/physical address size"""
|
||||
|
||||
leaf = 0x80000008
|
||||
physical_address_bits = cpuidfield(EAX, 7, 0, doc="# Physical Address bits")
|
||||
linear_address_bits = cpuidfield(EAX, 15, 8, doc="# Linear Address bits")
|
209
misc/config_tools/board_inspector/cpuparser/platformbase.py
Normal file
209
misc/config_tools/board_inspector/cpuparser/platformbase.py
Normal file
@ -0,0 +1,209 @@
|
||||
# Copyright (C) 2021 Intel Corporation. All rights reserved.
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
#
|
||||
|
||||
"""Base classes and infrastructure for CPUID and MSR decoding"""
|
||||
|
||||
from __future__ import print_function
|
||||
import subprocess
|
||||
import re
|
||||
import functools
|
||||
import inspect
|
||||
import operator
|
||||
import textwrap
|
||||
from collections import namedtuple
|
||||
|
||||
_wrapper = textwrap.TextWrapper(width=78, initial_indent=' ', subsequent_indent=' ')
|
||||
regex_hex = "0x[0-9a-f]+"
|
||||
|
||||
class cpuid_result(namedtuple('cpuid_result', ['eax', 'ebx', 'ecx', 'edx'])):
|
||||
__slots__ = ()
|
||||
|
||||
def __repr__(self):
|
||||
return "cpuid_result(eax={eax:#010x}, ebx={ebx:#010x}, ecx={ecx:#010x}, edx={edx:#010x})".format(**self._asdict())
|
||||
|
||||
def cpuid(cpu_id, leaf, subleaf):
|
||||
result = subprocess.run(["cpuid", "-l", str(leaf), "-s", str(subleaf), "-r"], stdout=subprocess.PIPE, check=True)
|
||||
stdout = result.stdout.decode("ascii").replace("\n", "")
|
||||
regex = re.compile(f"CPU {cpu_id}:[^:]*: eax=({regex_hex}) ebx=({regex_hex}) ecx=({regex_hex}) edx=({regex_hex})")
|
||||
m = regex.search(stdout)
|
||||
if m:
|
||||
regs = list(map(lambda idx: int(m.group(idx), base=16), range(1, 5)))
|
||||
else:
|
||||
regs = [0] * 4
|
||||
return cpuid_result(*regs)
|
||||
|
||||
class CPUID(object):
|
||||
# Subclasses must define a "leaf" field as part of the class definition.
|
||||
|
||||
def __init__(self, regs):
|
||||
self.regs = regs
|
||||
|
||||
@classmethod
|
||||
def read(cls, cpu_id, subleaf=0):
|
||||
r = cls(cpuid(cpu_id, cls.leaf, subleaf))
|
||||
r.cpu_id = cpu_id
|
||||
r.subleaf = subleaf
|
||||
return r
|
||||
|
||||
# FIXME: This allows getting subleaves, but requires having an instance of
|
||||
# the class first, which means always reading subleaf 0 and then the
|
||||
# desired subleaf.
|
||||
def __getitem__(self, subleaf):
|
||||
return self.read(self.cpu_id, subleaf)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.regs == other.regs
|
||||
|
||||
def __ne__(self, other):
|
||||
return self.regs != other.regs
|
||||
|
||||
def __str__(self):
|
||||
T = type(self)
|
||||
fields = dict((regnum, {}) for regnum in range(len(self.regs._fields)))
|
||||
properties = list()
|
||||
for field_name in dir(T):
|
||||
field = getattr(T, field_name)
|
||||
if isinstance(field, cpuidfield):
|
||||
fields[field.reg][field_name] = field
|
||||
elif isinstance(field, property):
|
||||
properties.append(field_name)
|
||||
|
||||
heading = "CPU ID {:#x} -- ".format(self.cpu_id)
|
||||
heading += "CPUID (EAX={:#x}".format(self.leaf)
|
||||
if self.subleaf:
|
||||
heading += ", ECX={:#x}".format(self.subleaf)
|
||||
heading += ")"
|
||||
s = heading + "\n" + "-"*len(heading) + "\n"
|
||||
doc = inspect.getdoc(self)
|
||||
if doc:
|
||||
s += doc + "\n"
|
||||
|
||||
def format_range(msb, lsb):
|
||||
if msb == lsb:
|
||||
return "[{}]".format(msb)
|
||||
return "[{}:{}]".format(msb, lsb)
|
||||
def format_field(msb, lsb, value):
|
||||
"""Field formatter that special-cases single bits and drops the 0x"""
|
||||
if msb == lsb:
|
||||
return str(value)
|
||||
return "{:#x}".format(value)
|
||||
for regnum, regname in enumerate(self.regs._fields):
|
||||
s += "\n"
|
||||
s1 = " {}={:#010x} ".format(regname, self.regs[regnum])
|
||||
s += s1
|
||||
inner = ("\n " + " " * len(s1)).join(
|
||||
"{}{} {}={}".format(regname, format_range(field.msb, field.lsb), field_name, format_field(field.msb, field.lsb, getattr(self, field_name)))
|
||||
for field_name, field in sorted(fields[regnum].items(), key=(lambda x: x[1].lsb))
|
||||
)
|
||||
if inner:
|
||||
s += " {}".format(inner)
|
||||
|
||||
properties = sorted(set(properties))
|
||||
if len(properties):
|
||||
s += "\n Attributes derived from one or more fields:"
|
||||
for property_name in properties:
|
||||
s += '\n'
|
||||
temp = "{}={}".format(property_name, getattr(self, property_name))
|
||||
s += '\n'.join(_wrapper.wrap(temp))
|
||||
return s
|
||||
|
||||
class cpuidfield(property):
|
||||
def __init__(self, reg, msb, lsb, doc="Bogus"):
|
||||
self.reg = reg
|
||||
self.msb = msb
|
||||
self.lsb = lsb
|
||||
|
||||
max_value = (1 << (msb - lsb + 1)) - 1
|
||||
field_mask = max_value << lsb
|
||||
|
||||
def getter(self):
|
||||
return (self.regs[reg] & field_mask) >> lsb
|
||||
super(cpuidfield, self).__init__(getter, doc=doc)
|
||||
|
||||
class MSR(object):
|
||||
# Subclasses must define a "addr" field as part of the class definition.
|
||||
|
||||
def __init__(self, value=0):
|
||||
self.value = value
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.value == other.value
|
||||
|
||||
def __ne__(self, other):
|
||||
return self.value != other.value
|
||||
|
||||
@classmethod
|
||||
def rdmsr(cls, cpu_id):
|
||||
r = cls(bits.rdmsr(cpu_id, cls.addr))
|
||||
r.cpu_id = cpu_id
|
||||
return r
|
||||
|
||||
def wrmsr(self, cpu_id=None):
|
||||
if cpu_id is None:
|
||||
cpu_id = self.cpu_id
|
||||
bits.wrmsr(cpu_id, self.addr, self.value)
|
||||
|
||||
def __str__(self):
|
||||
T = type(self)
|
||||
fields = {}
|
||||
properties = []
|
||||
for field_name in dir(T):
|
||||
field = getattr(T, field_name)
|
||||
if isinstance(field, msrfield):
|
||||
fields[field_name] = field
|
||||
elif isinstance(field, property):
|
||||
properties.append(field_name)
|
||||
|
||||
heading = "CPU ID {:#x} -- ".format(self.cpu_id)
|
||||
heading += "MSR {:#x}".format(self.addr)
|
||||
s = heading + "\n" + "-"*len(heading) + "\n"
|
||||
doc = inspect.getdoc(self)
|
||||
if doc:
|
||||
s += doc + "\n\n"
|
||||
s += "MSR {:#x}".format(self.addr)
|
||||
if self.value is None:
|
||||
s += ' value=GPF'
|
||||
return s
|
||||
|
||||
s += ' value={:#x}'.format(self.value)
|
||||
|
||||
for field_name, field in sorted(fields.items(), key=(lambda x: x[1].lsb)):
|
||||
s += '\n'
|
||||
temp = "[{}:{}] {}={:#x}".format(field.msb, field.lsb, field_name, getattr(self, field_name))
|
||||
# FIXME: check wrapper, and use a hanging indent to wrap the docstring to len(temp)+1
|
||||
if field.__doc__:
|
||||
temp += " " + inspect.getdoc(field)
|
||||
s += '\n'.join(_wrapper.wrap(temp))
|
||||
|
||||
if properties:
|
||||
s += "\n Attributes derived from one or more fields:"
|
||||
for property_name in sorted(properties):
|
||||
s += '\n'
|
||||
temp = "{}={}".format(property_name, getattr(self, property_name))
|
||||
# FIXME: check wrapper, get the property documentation string if any, and use a hanging indent to wrap the docstring to len(temp)+1
|
||||
s += '\n'.join(_wrapper.wrap(temp))
|
||||
return s
|
||||
|
||||
class msrfield(property):
|
||||
def __init__(self, msb, lsb, doc=None):
|
||||
self.msb = msb
|
||||
self.lsb = lsb
|
||||
|
||||
max_value = (1 << (msb - lsb + 1)) - 1
|
||||
field_mask = max_value << lsb
|
||||
|
||||
def getter(self):
|
||||
return (self.value & field_mask) >> lsb
|
||||
|
||||
def setter(self, value):
|
||||
if value > max_value:
|
||||
if msb == lsb:
|
||||
field = "[{0}]".format(msb)
|
||||
else:
|
||||
field = "[{0}:{1}]".format(msb, lsb)
|
||||
raise OverflowError("Value {value:#x} too big for MSR {self.addr:#x} field {field}".format(**locals()))
|
||||
self.value = (self.value & ~field_mask) | (value << lsb)
|
||||
|
||||
super(msrfield, self).__init__(getter, setter, doc=doc)
|
Loading…
Reference in New Issue
Block a user