xref: /openbmc/qemu/scripts/cpu-x86-uarch-abi.py (revision 15dbbeaff3c696be8c9c236ffb25d25ce21cba38)
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