14e2f5f3aSDaniel P. Berrangé#!/usr/bin/python3 24e2f5f3aSDaniel P. Berrangé# 34e2f5f3aSDaniel P. Berrangé# SPDX-License-Identifier: GPL-2.0-or-later 44e2f5f3aSDaniel P. Berrangé# 54e2f5f3aSDaniel P. Berrangé# A script to generate a CSV file showing the x86_64 ABI 64e2f5f3aSDaniel P. Berrangé# compatibility levels for each CPU model. 74e2f5f3aSDaniel P. Berrangé# 84e2f5f3aSDaniel P. Berrangé 937094b6dSJohn Snowfrom qemu.qmp.legacy import QEMUMonitorProtocol 104e2f5f3aSDaniel P. Berrangéimport sys 114e2f5f3aSDaniel P. Berrangé 1299221256SJohn Snowif len(sys.argv) != 2: 134e2f5f3aSDaniel P. Berrangé print("syntax: %s QMP-SOCK\n\n" % __file__ + 144e2f5f3aSDaniel P. Berrangé "Where QMP-SOCK points to a QEMU process such as\n\n" + 154e2f5f3aSDaniel P. Berrangé " # qemu-system-x86_64 -qmp unix:/tmp/qmp,server,nowait " + 164e2f5f3aSDaniel P. Berrangé "-display none -accel kvm", file=sys.stderr) 174e2f5f3aSDaniel P. Berrangé sys.exit(1) 184e2f5f3aSDaniel P. Berrangé 194e2f5f3aSDaniel P. Berrangé# Mandatory CPUID features for each microarch ABI level 204e2f5f3aSDaniel P. Berrangélevels = [ 214e2f5f3aSDaniel P. Berrangé [ # x86-64 baseline 224e2f5f3aSDaniel P. Berrangé "cmov", 234e2f5f3aSDaniel P. Berrangé "cx8", 244e2f5f3aSDaniel P. Berrangé "fpu", 254e2f5f3aSDaniel P. Berrangé "fxsr", 264e2f5f3aSDaniel P. Berrangé "mmx", 274e2f5f3aSDaniel P. Berrangé "syscall", 284e2f5f3aSDaniel P. Berrangé "sse", 294e2f5f3aSDaniel P. Berrangé "sse2", 304e2f5f3aSDaniel P. Berrangé ], 314e2f5f3aSDaniel P. Berrangé [ # x86-64-v2 324e2f5f3aSDaniel P. Berrangé "cx16", 334e2f5f3aSDaniel P. Berrangé "lahf-lm", 344e2f5f3aSDaniel P. Berrangé "popcnt", 354e2f5f3aSDaniel P. Berrangé "pni", 364e2f5f3aSDaniel P. Berrangé "sse4.1", 374e2f5f3aSDaniel P. Berrangé "sse4.2", 384e2f5f3aSDaniel P. Berrangé "ssse3", 394e2f5f3aSDaniel P. Berrangé ], 404e2f5f3aSDaniel P. Berrangé [ # x86-64-v3 414e2f5f3aSDaniel P. Berrangé "avx", 424e2f5f3aSDaniel P. Berrangé "avx2", 434e2f5f3aSDaniel P. Berrangé "bmi1", 444e2f5f3aSDaniel P. Berrangé "bmi2", 454e2f5f3aSDaniel P. Berrangé "f16c", 464e2f5f3aSDaniel P. Berrangé "fma", 474e2f5f3aSDaniel P. Berrangé "abm", 484e2f5f3aSDaniel P. Berrangé "movbe", 494e2f5f3aSDaniel P. Berrangé ], 504e2f5f3aSDaniel P. Berrangé [ # x86-64-v4 514e2f5f3aSDaniel P. Berrangé "avx512f", 524e2f5f3aSDaniel P. Berrangé "avx512bw", 534e2f5f3aSDaniel P. Berrangé "avx512cd", 544e2f5f3aSDaniel P. Berrangé "avx512dq", 554e2f5f3aSDaniel P. Berrangé "avx512vl", 564e2f5f3aSDaniel P. Berrangé ], 574e2f5f3aSDaniel P. Berrangé] 584e2f5f3aSDaniel P. Berrangé 594e2f5f3aSDaniel P. Berrangé# Assumes externally launched process such as 604e2f5f3aSDaniel P. Berrangé# 614e2f5f3aSDaniel P. Berrangé# qemu-system-x86_64 -qmp unix:/tmp/qmp,server,nowait -display none -accel kvm 624e2f5f3aSDaniel P. Berrangé# 634e2f5f3aSDaniel P. Berrangé# Note different results will be obtained with TCG, as 644e2f5f3aSDaniel P. Berrangé# TCG masks out certain features otherwise present in 654e2f5f3aSDaniel P. Berrangé# the CPU model definitions, as does KVM. 664e2f5f3aSDaniel P. Berrangé 674e2f5f3aSDaniel P. Berrangé 684e2f5f3aSDaniel P. Berrangésock = sys.argv[1] 690665410dSJohn Snowshell = QEMUMonitorProtocol(sock) 704e2f5f3aSDaniel P. Berrangéshell.connect() 714e2f5f3aSDaniel P. Berrangé 72684750abSVladimir Sementsov-Ogievskiymodels = shell.cmd("query-cpu-definitions") 734e2f5f3aSDaniel P. Berrangé 744e2f5f3aSDaniel P. Berrangé# These QMP props don't correspond to CPUID fatures 754e2f5f3aSDaniel P. Berrangé# so ignore them 764e2f5f3aSDaniel P. Berrangéskip = [ 774e2f5f3aSDaniel P. Berrangé "family", 784e2f5f3aSDaniel P. Berrangé "min-level", 794e2f5f3aSDaniel P. Berrangé "min-xlevel", 804e2f5f3aSDaniel P. Berrangé "vendor", 814e2f5f3aSDaniel P. Berrangé "model", 824e2f5f3aSDaniel P. Berrangé "model-id", 834e2f5f3aSDaniel P. Berrangé "stepping", 844e2f5f3aSDaniel P. Berrangé] 854e2f5f3aSDaniel P. Berrangé 864e2f5f3aSDaniel P. Berrangénames = [] 874e2f5f3aSDaniel P. Berrangé 887f521b02SVladimir Sementsov-Ogievskiyfor model in models: 894e2f5f3aSDaniel P. Berrangé if "alias-of" in model: 904e2f5f3aSDaniel P. Berrangé continue 914e2f5f3aSDaniel P. Berrangé names.append(model["name"]) 924e2f5f3aSDaniel P. Berrangé 934e2f5f3aSDaniel P. Berrangémodels = {} 944e2f5f3aSDaniel P. Berrangé 954e2f5f3aSDaniel P. Berrangéfor name in sorted(names): 96684750abSVladimir Sementsov-Ogievskiy cpu = shell.cmd("query-cpu-model-expansion", 97*3e7ebf58SZhao Liu type="static", 98*3e7ebf58SZhao Liu model={ "name": name }) 994e2f5f3aSDaniel P. Berrangé 1004e2f5f3aSDaniel P. Berrangé got = {} 1017f521b02SVladimir Sementsov-Ogievskiy for (feature, present) in cpu["model"]["props"].items(): 1024e2f5f3aSDaniel P. Berrangé if present and feature not in skip: 1034e2f5f3aSDaniel P. Berrangé got[feature] = True 1044e2f5f3aSDaniel P. Berrangé 1054e2f5f3aSDaniel P. Berrangé if name in ["host", "max", "base"]: 1064e2f5f3aSDaniel P. Berrangé continue 1074e2f5f3aSDaniel P. Berrangé 1084e2f5f3aSDaniel P. Berrangé models[name] = { 1094e2f5f3aSDaniel P. Berrangé # Dict of all present features in this CPU model 1104e2f5f3aSDaniel P. Berrangé "features": got, 1114e2f5f3aSDaniel P. Berrangé 1124e2f5f3aSDaniel P. Berrangé # Whether each x86-64 ABI level is satisfied 1134e2f5f3aSDaniel P. Berrangé "levels": [False, False, False, False], 1144e2f5f3aSDaniel P. Berrangé 1154e2f5f3aSDaniel P. Berrangé # Number of extra CPUID features compared to the x86-64 ABI level 1164e2f5f3aSDaniel P. Berrangé "distance":[-1, -1, -1, -1], 1174e2f5f3aSDaniel P. Berrangé 1184e2f5f3aSDaniel P. Berrangé # CPUID features present in model, but not in ABI level 1194e2f5f3aSDaniel P. Berrangé "delta":[[], [], [], []], 1204e2f5f3aSDaniel P. Berrangé 1214e2f5f3aSDaniel P. Berrangé # CPUID features in ABI level but not present in model 1224e2f5f3aSDaniel P. Berrangé "missing": [[], [], [], []], 1234e2f5f3aSDaniel P. Berrangé } 1244e2f5f3aSDaniel P. Berrangé 1254e2f5f3aSDaniel P. Berrangé 1264e2f5f3aSDaniel P. Berrangé# Calculate whether the CPU models satisfy each ABI level 1274e2f5f3aSDaniel P. Berrangéfor name in models.keys(): 1284e2f5f3aSDaniel P. Berrangé for level in range(len(levels)): 1294e2f5f3aSDaniel P. Berrangé got = set(models[name]["features"]) 1304e2f5f3aSDaniel P. Berrangé want = set(levels[level]) 1314e2f5f3aSDaniel P. Berrangé missing = want - got 1324e2f5f3aSDaniel P. Berrangé match = True 1334e2f5f3aSDaniel P. Berrangé if len(missing) > 0: 1344e2f5f3aSDaniel P. Berrangé match = False 1354e2f5f3aSDaniel P. Berrangé models[name]["levels"][level] = match 1364e2f5f3aSDaniel P. Berrangé models[name]["missing"][level] = missing 1374e2f5f3aSDaniel P. Berrangé 1384e2f5f3aSDaniel P. Berrangé# Cache list of CPU models satisfying each ABI level 1394e2f5f3aSDaniel P. Berrangéabi_models = [ 1404e2f5f3aSDaniel P. Berrangé [], 1414e2f5f3aSDaniel P. Berrangé [], 1424e2f5f3aSDaniel P. Berrangé [], 1434e2f5f3aSDaniel P. Berrangé [], 1444e2f5f3aSDaniel P. Berrangé] 1454e2f5f3aSDaniel P. Berrangé 1464e2f5f3aSDaniel P. Berrangéfor name in models.keys(): 1474e2f5f3aSDaniel P. Berrangé for level in range(len(levels)): 1484e2f5f3aSDaniel P. Berrangé if models[name]["levels"][level]: 1494e2f5f3aSDaniel P. Berrangé abi_models[level].append(name) 1504e2f5f3aSDaniel P. Berrangé 1514e2f5f3aSDaniel P. Berrangé 1524e2f5f3aSDaniel P. Berrangéfor level in range(len(abi_models)): 1534e2f5f3aSDaniel P. Berrangé # Find the union of features in all CPU models satisfying this ABI 1544e2f5f3aSDaniel P. Berrangé allfeatures = {} 1554e2f5f3aSDaniel P. Berrangé for name in abi_models[level]: 1564e2f5f3aSDaniel P. Berrangé for feat in models[name]["features"]: 1574e2f5f3aSDaniel P. Berrangé allfeatures[feat] = True 1584e2f5f3aSDaniel P. Berrangé 1594e2f5f3aSDaniel P. Berrangé # Find the intersection of features in all CPU models satisfying this ABI 1604e2f5f3aSDaniel P. Berrangé commonfeatures = [] 1614e2f5f3aSDaniel P. Berrangé for feat in allfeatures: 1624e2f5f3aSDaniel P. Berrangé present = True 1634e2f5f3aSDaniel P. Berrangé for name in models.keys(): 1644e2f5f3aSDaniel P. Berrangé if not models[name]["levels"][level]: 1654e2f5f3aSDaniel P. Berrangé continue 1664e2f5f3aSDaniel P. Berrangé if feat not in models[name]["features"]: 1674e2f5f3aSDaniel P. Berrangé present = False 1684e2f5f3aSDaniel P. Berrangé if present: 1694e2f5f3aSDaniel P. Berrangé commonfeatures.append(feat) 1704e2f5f3aSDaniel P. Berrangé 1714e2f5f3aSDaniel P. Berrangé # Determine how many extra features are present compared to the lowest 1724e2f5f3aSDaniel P. Berrangé # common denominator 1734e2f5f3aSDaniel P. Berrangé for name in models.keys(): 1744e2f5f3aSDaniel P. Berrangé if not models[name]["levels"][level]: 1754e2f5f3aSDaniel P. Berrangé continue 1764e2f5f3aSDaniel P. Berrangé 1774e2f5f3aSDaniel P. Berrangé delta = set(models[name]["features"].keys()) - set(commonfeatures) 1784e2f5f3aSDaniel P. Berrangé models[name]["distance"][level] = len(delta) 1794e2f5f3aSDaniel P. Berrangé models[name]["delta"][level] = delta 1804e2f5f3aSDaniel P. Berrangé 1814e2f5f3aSDaniel P. Berrangédef print_uarch_abi_csv(): 1824e2f5f3aSDaniel P. Berrangé print("Model,baseline,v2,v3,v4") 1834e2f5f3aSDaniel P. Berrangé for name in models.keys(): 1844e2f5f3aSDaniel P. Berrangé print(name, end="") 1854e2f5f3aSDaniel P. Berrangé for level in range(len(levels)): 1864e2f5f3aSDaniel P. Berrangé if models[name]["levels"][level]: 1874e2f5f3aSDaniel P. Berrangé print(",✅", end="") 1884e2f5f3aSDaniel P. Berrangé else: 1894e2f5f3aSDaniel P. Berrangé print(",", end="") 1904e2f5f3aSDaniel P. Berrangé print() 1914e2f5f3aSDaniel P. Berrangé 1924e2f5f3aSDaniel P. Berrangéprint_uarch_abi_csv() 193