Signed-off-by: Tim Wiederhake <twiederh(a)redhat.com>
---
src/cpu_map/x86_features.py | 119 ++++++++++++++++++++++++++++++++++++
1 file changed, 119 insertions(+)
create mode 100755 src/cpu_map/x86_features.py
diff --git a/src/cpu_map/x86_features.py b/src/cpu_map/x86_features.py
new file mode 100755
index 0000000000..5bc7e06216
--- /dev/null
+++ b/src/cpu_map/x86_features.py
@@ -0,0 +1,119 @@
+#!/bin/env python3
+
+import os
+import pycpuinfo
+
+non_migratable = (
+ "invtsc",
+ "xsaves",
+)
+
+family_x86 = pycpuinfo.Family.find("x86")
+
+features_cpuid = dict()
+features_msr = dict()
+
+
+def cpuid_to_reg_value(data):
+ if data[2]:
+ return "eax", data[2]
+ if data[3]:
+ return "ebx", data[3]
+ if data[4]:
+ return "ecx", data[4]
+ if data[5]:
+ return "edx", data[5]
+
+
+def add_cpuid(feature):
+ name = feature.name("libvirt")
+ data = feature.extra_x86_cpuid()
+ reg_value = cpuid_to_reg_value(data)
+
+ if data[0] not in features_cpuid:
+ features_cpuid[data[0]] = dict()
+
+ if data[1] not in features_cpuid[data[0]]:
+ features_cpuid[data[0]][data[1]] = dict()
+
+ if reg_value[0] not in features_cpuid[data[0]][data[1]]:
+ features_cpuid[data[0]][data[1]][reg_value[0]] = set()
+
+ features_cpuid[data[0]][data[1]][reg_value[0]].add((
+ reg_value[1],
+ name,
+ ))
+
+
+def add_msr(feature):
+ data = feature.extra_x86_msr()
+ if data[0] not in features_msr:
+ features_msr[data[0]] = set()
+
+ features_msr[data[0]].add((
+ data[2],
+ data[1],
+ feature.name("libvirt"),
+ ))
+
+
+def print_feature_cpuid(f):
+ tmpl_ecx = (
+ " <!-- cpuid level 0x{0:08x}, ecx 0x{1:04x} ({2}) -->\n",
+ " <cpuid eax_in='0x{0:08x}' ecx_in='0x{1:08x}'
{2}='0x{3:08x}'/>\n"
+ )
+ tmpl_any = (
+ " <!-- cpuid level 0x{0:08x} ({2}) -->\n",
+ " <cpuid eax_in='0x{0:08x}'
{2}='0x{3:08x}'/>\n"
+ )
+
+ for eax in sorted(features_cpuid):
+ for ecx in sorted(features_cpuid[eax]):
+ if ecx == pycpuinfo.x86.CPUINFO_X86_CPUID_ECX_NONE:
+ template = tmpl_any
+ else:
+ template = tmpl_ecx
+
+ for reg in sorted(features_cpuid[eax][ecx]):
+ f.write(template[0].format(eax, ecx, reg))
+ for data in sorted(features_cpuid[eax][ecx][reg]):
+ extra = ""
+ if data[1] in non_migratable:
+ extra = " migratable='no'"
+ f.write(" <feature
name='{}'{}>\n".format(data[1], extra))
+ f.write(template[1].format(eax, ecx, reg, data[0]))
+ f.write(" </feature>\n")
+ f.write("\n")
+
+
+def print_feature_msr(f):
+ template = " <msr index='0x{:08x}' edx='0x{:08x}'
eax='0x{:08x}'/>\n"
+ for msr in sorted(features_msr):
+ f.write(" <!-- msr 0x{:08x} -->\n".format(msr))
+ for data in sorted(features_msr[msr]):
+ f.write(" <feature name='{}'>\n".format(data[2]))
+ f.write(template.format(msr, data[0], data[1]))
+ f.write(" </feature>\n")
+ f.write("\n")
+
+
+for feature in pycpuinfo.features():
+ if feature.family() != family_x86:
+ continue
+
+ if feature.extra_x86_cpuid():
+ add_cpuid(feature)
+ elif feature.extra_x86_msr():
+ add_msr(feature)
+
+
+filename = os.path.join(os.path.dirname(__file__), "x86_features.xml")
+with open(filename, "tw") as f:
+ f.write(
+ "<!--\n After adding new features, update existing test files
with\n"
+ "\n tests/cputestdata/cpu-data.py diff tests/cputestdata/x86_64-"
+ "cpuid-*.json\n\n-->\n")
+ f.write("<cpus>\n")
+ print_feature_cpuid(f)
+ print_feature_msr(f)
+ f.write("</cpus>\n")
--
2.39.2