2019-02-21 19:28:49 +00:00
|
|
|
#!/usr/bin/env python3
|
2017-02-01 16:48:41 +00:00
|
|
|
|
2021-01-04 11:30:11 +00:00
|
|
|
import argparse
|
2018-01-05 13:35:42 +00:00
|
|
|
import os
|
2017-02-01 16:48:41 +00:00
|
|
|
import sys
|
|
|
|
import json
|
2021-01-04 11:30:12 +00:00
|
|
|
import xml.etree.ElementTree
|
2017-02-01 16:48:41 +00:00
|
|
|
|
2019-09-24 12:55:56 +00:00
|
|
|
|
2019-04-02 17:02:04 +00:00
|
|
|
def checkFeature(cpuData, feature):
|
|
|
|
if feature["type"] == "cpuid":
|
2021-01-04 11:30:15 +00:00
|
|
|
# cpuData["cpuid"][eax_in][ecx_in] = {eax:, ebx:, ecx:, edx:}
|
|
|
|
keyList = ["type", "eax_in", "ecx_in"]
|
|
|
|
regList = ["eax", "ebx", "ecx", "edx"]
|
|
|
|
elif feature["type"] == "msr":
|
|
|
|
# cpuData["msr"][index] = {eax:, edx:}
|
|
|
|
keyList = ["type", "index"]
|
|
|
|
regList = ["eax", "edx"]
|
|
|
|
else:
|
|
|
|
return False
|
|
|
|
|
|
|
|
for key in keyList:
|
|
|
|
if feature[key] not in cpuData:
|
|
|
|
return False
|
|
|
|
cpuData = cpuData[feature[key]]
|
2019-04-02 17:02:04 +00:00
|
|
|
|
2021-01-04 11:30:15 +00:00
|
|
|
for reg in regList:
|
|
|
|
if feature[reg] > 0 and feature[reg] == feature[reg] & cpuData[reg]:
|
|
|
|
return True
|
|
|
|
return False
|
2019-04-02 17:02:04 +00:00
|
|
|
|
|
|
|
|
|
|
|
def addFeature(cpuData, feature):
|
|
|
|
if feature["type"] == "cpuid":
|
2021-01-04 11:30:14 +00:00
|
|
|
# cpuData["cpuid"][eax_in][ecx_in] = {eax:, ebx:, ecx:, edx:}
|
|
|
|
keyList = ["type", "eax_in", "ecx_in"]
|
|
|
|
regList = ["eax", "ebx", "ecx", "edx"]
|
2019-04-01 16:24:05 +00:00
|
|
|
elif feature["type"] == "msr":
|
2021-01-04 11:30:14 +00:00
|
|
|
# cpuData["msr"][index] = {eax:, edx:}
|
|
|
|
keyList = ["type", "index"]
|
|
|
|
regList = ["eax", "edx"]
|
|
|
|
else:
|
|
|
|
return
|
|
|
|
|
|
|
|
for key in keyList:
|
|
|
|
if feature[key] not in cpuData:
|
|
|
|
cpuData[feature[key]] = dict()
|
|
|
|
cpuData = cpuData[feature[key]]
|
|
|
|
|
|
|
|
for reg in regList:
|
|
|
|
cpuData[reg] = cpuData.get(reg, 0) | feature[reg]
|
2019-04-02 17:02:04 +00:00
|
|
|
|
|
|
|
|
2017-03-16 11:25:30 +00:00
|
|
|
def parseQemu(path, features):
|
2019-04-01 15:06:59 +00:00
|
|
|
cpuData = {}
|
2017-03-16 11:25:30 +00:00
|
|
|
with open(path, "r") as f:
|
2017-09-26 19:08:37 +00:00
|
|
|
data, pos = json.JSONDecoder().raw_decode(f.read())
|
2017-03-16 11:25:30 +00:00
|
|
|
|
2019-02-21 19:28:49 +00:00
|
|
|
for (prop, val) in data["return"]["model"]["props"].items():
|
2017-03-16 11:25:30 +00:00
|
|
|
if val and prop in features:
|
2019-04-01 15:06:59 +00:00
|
|
|
addFeature(cpuData, features[prop])
|
2017-03-16 11:25:30 +00:00
|
|
|
|
2019-04-01 15:06:59 +00:00
|
|
|
return cpuData
|
2017-03-16 11:25:30 +00:00
|
|
|
|
|
|
|
|
2019-04-01 15:06:59 +00:00
|
|
|
def parseCPUData(path):
|
2021-01-04 11:30:13 +00:00
|
|
|
cpuData = dict()
|
|
|
|
for f in xml.etree.ElementTree.parse(path).getroot():
|
|
|
|
if f.tag == "cpuid":
|
|
|
|
reg_list = ["eax_in", "ecx_in", "eax", "ebx", "ecx", "edx"]
|
|
|
|
elif f.tag == "msr":
|
|
|
|
reg_list = ["index", "eax", "edx"]
|
|
|
|
else:
|
|
|
|
continue
|
2017-03-16 11:25:30 +00:00
|
|
|
|
2021-01-04 11:30:13 +00:00
|
|
|
feature = {"type": f.tag}
|
|
|
|
for reg in reg_list:
|
|
|
|
feature[reg] = int(f.attrib.get(reg, "0"), 0)
|
2019-04-01 15:06:59 +00:00
|
|
|
addFeature(cpuData, feature)
|
|
|
|
return cpuData
|
2017-03-16 11:25:30 +00:00
|
|
|
|
|
|
|
|
2018-01-05 13:35:42 +00:00
|
|
|
def parseMap():
|
|
|
|
path = os.path.dirname(sys.argv[0])
|
2019-02-21 19:10:48 +00:00
|
|
|
path = os.path.join(path, "..", "..", "src", "cpu_map", "x86_features.xml")
|
2018-01-05 13:35:42 +00:00
|
|
|
|
2021-01-04 11:30:12 +00:00
|
|
|
cpuMap = dict()
|
|
|
|
for f in xml.etree.ElementTree.parse(path).getroot().iter("feature"):
|
|
|
|
if f[0].tag == "cpuid":
|
|
|
|
reg_list = ["eax_in", "ecx_in", "eax", "ebx", "ecx", "edx"]
|
|
|
|
elif f[0].tag == "msr":
|
|
|
|
reg_list = ["index", "eax", "edx"]
|
|
|
|
else:
|
|
|
|
continue
|
2018-01-05 13:35:42 +00:00
|
|
|
|
2021-01-04 11:30:12 +00:00
|
|
|
feature = {"type": f[0].tag}
|
|
|
|
for reg in reg_list:
|
|
|
|
feature[reg] = int(f[0].attrib.get(reg, "0"), 0)
|
|
|
|
cpuMap[f.attrib["name"]] = feature
|
2018-01-05 13:35:42 +00:00
|
|
|
return cpuMap
|
|
|
|
|
|
|
|
|
2019-04-02 17:02:04 +00:00
|
|
|
def formatCPUData(cpuData, path, comment):
|
2019-02-21 19:28:49 +00:00
|
|
|
print(path)
|
2017-03-16 11:25:30 +00:00
|
|
|
with open(path, "w") as f:
|
|
|
|
f.write("<!-- " + comment + " -->\n")
|
|
|
|
f.write("<cpudata arch='x86'>\n")
|
2019-04-02 17:02:04 +00:00
|
|
|
|
|
|
|
cpuid = cpuData["cpuid"]
|
2019-04-01 17:23:01 +00:00
|
|
|
for eax_in in sorted(cpuid.keys()):
|
|
|
|
for ecx_in in sorted(cpuid[eax_in].keys()):
|
|
|
|
leaf = cpuid[eax_in][ecx_in]
|
2017-03-16 11:25:30 +00:00
|
|
|
line = (" <cpuid eax_in='0x%08x' ecx_in='0x%02x' "
|
|
|
|
"eax='0x%08x' ebx='0x%08x' "
|
|
|
|
"ecx='0x%08x' edx='0x%08x'/>\n")
|
2018-03-20 06:48:47 +00:00
|
|
|
f.write(line % (
|
2019-04-01 17:23:01 +00:00
|
|
|
eax_in, ecx_in,
|
2017-03-16 11:25:30 +00:00
|
|
|
leaf["eax"], leaf["ebx"], leaf["ecx"], leaf["edx"]))
|
2019-04-01 16:24:05 +00:00
|
|
|
|
|
|
|
if "msr" in cpuData:
|
|
|
|
msr = cpuData["msr"]
|
|
|
|
for index in sorted(msr.keys()):
|
2019-09-24 15:47:02 +00:00
|
|
|
f.write(" <msr index='0x%x' edx='0x%08x' eax='0x%08x'/>\n" %
|
|
|
|
(index, msr[index]['edx'], msr[index]['eax']))
|
2019-04-01 16:24:05 +00:00
|
|
|
|
2017-03-16 11:25:30 +00:00
|
|
|
f.write("</cpudata>\n")
|
|
|
|
|
|
|
|
|
2021-01-04 11:30:11 +00:00
|
|
|
def diff(args):
|
2018-01-05 13:35:42 +00:00
|
|
|
cpuMap = parseMap()
|
2021-01-04 11:30:11 +00:00
|
|
|
|
|
|
|
for jsonFile in args.json_files:
|
|
|
|
cpuDataFile = jsonFile.replace(".json", ".xml")
|
|
|
|
enabledFile = jsonFile.replace(".json", "-enabled.xml")
|
|
|
|
disabledFile = jsonFile.replace(".json", "-disabled.xml")
|
|
|
|
|
|
|
|
cpuData = parseCPUData(cpuDataFile)
|
|
|
|
qemu = parseQemu(jsonFile, cpuMap)
|
|
|
|
|
|
|
|
enabled = dict()
|
|
|
|
disabled = dict()
|
|
|
|
for feature in cpuMap.values():
|
|
|
|
if checkFeature(qemu, feature):
|
|
|
|
addFeature(enabled, feature)
|
|
|
|
elif checkFeature(cpuData, feature):
|
|
|
|
addFeature(disabled, feature)
|
|
|
|
|
|
|
|
formatCPUData(enabled, enabledFile, "Features enabled by QEMU")
|
|
|
|
formatCPUData(disabled, disabledFile, "Features disabled by QEMU")
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
parser = argparse.ArgumentParser(description="Diff cpuid results")
|
|
|
|
subparsers = parser.add_subparsers(dest="action", required=True)
|
|
|
|
diffparser = subparsers.add_parser(
|
|
|
|
"diff",
|
|
|
|
help="Diff json description of CPU model against known features.")
|
|
|
|
diffparser.add_argument(
|
|
|
|
"json_files",
|
|
|
|
nargs="+",
|
|
|
|
metavar="FILE",
|
|
|
|
type=os.path.realpath,
|
|
|
|
help="Path to one or more json CPU model descriptions.")
|
|
|
|
args = parser.parse_args()
|
|
|
|
|
|
|
|
diff(args)
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
main()
|