]> Git Repo - qemu.git/blob - scripts/cpu-x86-uarch-abi.py
works with less than base ISA qemu-system-riscv32 -M virt -bios none -kernel output...
[qemu.git] / scripts / cpu-x86-uarch-abi.py
1 #!/usr/bin/python3
2 #
3 # SPDX-License-Identifier: GPL-2.0-or-later
4 #
5 # A script to generate a CSV file showing the x86_64 ABI
6 # compatibility levels for each CPU model.
7 #
8
9 from qemu.qmp.legacy import QEMUMonitorProtocol
10 import sys
11
12 if len(sys.argv) != 2:
13     print("syntax: %s QMP-SOCK\n\n" % __file__ +
14           "Where QMP-SOCK points to a QEMU process such as\n\n" +
15           " # qemu-system-x86_64 -qmp unix:/tmp/qmp,server,nowait " +
16           "-display none -accel kvm", file=sys.stderr)
17     sys.exit(1)
18
19 # Mandatory CPUID features for each microarch ABI level
20 levels = [
21     [ # x86-64 baseline
22         "cmov",
23         "cx8",
24         "fpu",
25         "fxsr",
26         "mmx",
27         "syscall",
28         "sse",
29         "sse2",
30     ],
31     [ # x86-64-v2
32         "cx16",
33         "lahf-lm",
34         "popcnt",
35         "pni",
36         "sse4.1",
37         "sse4.2",
38         "ssse3",
39     ],
40     [ # x86-64-v3
41         "avx",
42         "avx2",
43         "bmi1",
44         "bmi2",
45         "f16c",
46         "fma",
47         "abm",
48         "movbe",
49     ],
50     [ # x86-64-v4
51         "avx512f",
52         "avx512bw",
53         "avx512cd",
54         "avx512dq",
55         "avx512vl",
56     ],
57 ]
58
59 # Assumes externally launched process such as
60 #
61 #   qemu-system-x86_64 -qmp unix:/tmp/qmp,server,nowait -display none -accel kvm
62 #
63 # Note different results will be obtained with TCG, as
64 # TCG masks out certain features otherwise present in
65 # the CPU model definitions, as does KVM.
66
67
68 sock = sys.argv[1]
69 shell = QEMUMonitorProtocol(sock)
70 shell.connect()
71
72 models = shell.cmd("query-cpu-definitions")
73
74 # These QMP props don't correspond to CPUID fatures
75 # so ignore them
76 skip = [
77     "family",
78     "min-level",
79     "min-xlevel",
80     "vendor",
81     "model",
82     "model-id",
83     "stepping",
84 ]
85
86 names = []
87
88 for model in models["return"]:
89     if "alias-of" in model:
90         continue
91     names.append(model["name"])
92
93 models = {}
94
95 for name in sorted(names):
96     cpu = shell.cmd("query-cpu-model-expansion",
97                      { "type": "static",
98                        "model": { "name": name }})
99
100     got = {}
101     for (feature, present) in cpu["return"]["model"]["props"].items():
102         if present and feature not in skip:
103             got[feature] = True
104
105     if name in ["host", "max", "base"]:
106         continue
107
108     models[name] = {
109         # Dict of all present features in this CPU model
110         "features": got,
111
112         # Whether each x86-64 ABI level is satisfied
113         "levels": [False, False, False, False],
114
115         # Number of extra CPUID features compared to the x86-64 ABI level
116         "distance":[-1, -1, -1, -1],
117
118         # CPUID features present in model, but not in ABI level
119         "delta":[[], [], [], []],
120
121         # CPUID features in ABI level but not present in model
122         "missing": [[], [], [], []],
123     }
124
125
126 # Calculate whether the CPU models satisfy each ABI level
127 for name in models.keys():
128     for level in range(len(levels)):
129         got = set(models[name]["features"])
130         want = set(levels[level])
131         missing = want - got
132         match = True
133         if len(missing) > 0:
134             match = False
135         models[name]["levels"][level] = match
136         models[name]["missing"][level] = missing
137
138 # Cache list of CPU models satisfying each ABI level
139 abi_models = [
140     [],
141     [],
142     [],
143     [],
144 ]
145
146 for name in models.keys():
147     for level in range(len(levels)):
148         if models[name]["levels"][level]:
149             abi_models[level].append(name)
150
151
152 for level in range(len(abi_models)):
153     # Find the union of features in all CPU models satisfying this ABI
154     allfeatures = {}
155     for name in abi_models[level]:
156         for feat in models[name]["features"]:
157             allfeatures[feat] = True
158
159     # Find the intersection of features in all CPU models satisfying this ABI
160     commonfeatures = []
161     for feat in allfeatures:
162         present = True
163         for name in models.keys():
164             if not models[name]["levels"][level]:
165                 continue
166             if feat not in models[name]["features"]:
167                 present = False
168         if present:
169             commonfeatures.append(feat)
170
171     # Determine how many extra features are present compared to the lowest
172     # common denominator
173     for name in models.keys():
174         if not models[name]["levels"][level]:
175             continue
176
177         delta = set(models[name]["features"].keys()) - set(commonfeatures)
178         models[name]["distance"][level] = len(delta)
179         models[name]["delta"][level] = delta
180
181 def print_uarch_abi_csv():
182     print("# Automatically generated from '%s'" % __file__)
183     print("Model,baseline,v2,v3,v4")
184     for name in models.keys():
185         print(name, end="")
186         for level in range(len(levels)):
187             if models[name]["levels"][level]:
188                 print(",✅", end="")
189             else:
190                 print(",", end="")
191         print()
192
193 print_uarch_abi_csv()
This page took 0.036154 seconds and 4 git commands to generate.