This script is intended to help in synchronizing i386 QEMU cpu feature definitions with libvirt. QEMU's attribute list for the "max-x86_64-cpu" contains non-cpu-feature items and needs to be filtered before being useful. Signed-off-by: Tim Wiederhake <twiederh@xxxxxxxxxx> --- src/cpu_map/sync_qemu_features_i386.py | 278 +++++++++++++++++++++++++ 1 file changed, 278 insertions(+) create mode 100755 src/cpu_map/sync_qemu_features_i386.py diff --git a/src/cpu_map/sync_qemu_features_i386.py b/src/cpu_map/sync_qemu_features_i386.py new file mode 100755 index 0000000000..fba7d35609 --- /dev/null +++ b/src/cpu_map/sync_qemu_features_i386.py @@ -0,0 +1,278 @@ +#!/usr/bin/env python3 + +import argparse +import json +import subprocess +import xml.etree.ElementTree + + +def ignore_feature(feature): + ignored_features = [ + # VIA/Cyrix/Centaur-defined CPU features + # CPUID level 0xC0000001, word 5 + "ace2", + "ace2-en", + "phe", + "phe-en", + "pmm", + "pmm-en", + "xcrypt", + "xcrypt-en", + "xstore", + "xstore-en", + + # non-features + "check", + "cpuid-0xb", + "enforce", + "fill-mtrr-mask", + "full-cpuid-auto-level", + "full-width-write", + "host-cache-info", + "host-phys-bits", + "hotpluggable", + "hotplugged", + "hv-apicv", + "hv-avic", + "hv-crash", + "hv-emsr-bitmap", + "hv-enforce-cpuid", + "hv-evmcs", + "hv-frequencies", + "hv-ipi", + "hv-passthrough", + "hv-reenlightenment", + "hv-relaxed", + "hv-reset", + "hv-runtime", + "hv-stimer", + "hv-stimer-direct", + "hv-syndbg", + "hv-synic", + "hv-time", + "hv-tlbflush", + "hv-tlbflush-direct", + "hv-tlbflush-ext", + "hv-vapic", + "hv-vpindex", + "hv-xmm-input", + "kvm", + "kvm-asyncpf", + "kvm-asyncpf-int", + "kvm-hint-dedicated", + "kvm-mmu", + "kvm-msi-ext-dest-id", + "kvm-no-smi-migration", + "kvm-nopiodelay", + "kvm-poll-control", + "kvm-pv-enforce-cpuid", + "kvm-pv-eoi", + "kvm-pv-ipi", + "kvm-pv-sched-yield", + "kvm-pv-tlb-flush", + "kvm-pv-unhalt", + "kvm-steal-time", + "kvm_asyncpf", + "kvm_asyncpf_int", + "kvm_mmu", + "kvm_nopiodelay", + "kvm_poll_control", + "kvm_pv_eoi", + "kvm_pv_unhalt", + "kvm_steal_time", + "kvmclock", + "kvmclock-stable-bit", + "l3-cache", + "legacy-cache", + "lmce", + "migratable", + "pmu", + "realized", + "start-powered-off", + "tcg-cpuid", + "vmware-cpuid-freq", + "vmx-activity-hlt", + "vmx-activity-shutdown", + "vmx-activity-wait-sipi", + "vmx-apicv-register", + "vmx-apicv-vid", + "vmx-apicv-x2apic", + "vmx-apicv-xapic", + "vmx-cr3-load-noexit", + "vmx-cr3-store-noexit", + "vmx-cr8-load-exit", + "vmx-cr8-store-exit", + "vmx-desc-exit", + "vmx-encls-exit", + "vmx-entry-ia32e-mode", + "vmx-entry-load-bndcfgs", + "vmx-entry-load-efer", + "vmx-entry-load-pat", + "vmx-entry-load-perf-global-ctrl", + "vmx-entry-load-pkrs", + "vmx-entry-load-rtit-ctl", + "vmx-entry-noload-debugctl", + "vmx-ept", + "vmx-ept-1gb", + "vmx-ept-2mb", + "vmx-ept-advanced-exitinfo", + "vmx-ept-execonly", + "vmx-eptad", + "vmx-eptp-switching", + "vmx-exit-ack-intr", + "vmx-exit-clear-bndcfgs", + "vmx-exit-clear-rtit-ctl", + "vmx-exit-load-efer", + "vmx-exit-load-pat", + "vmx-exit-load-perf-global-ctrl", + "vmx-exit-load-pkrs", + "vmx-exit-nosave-debugctl", + "vmx-exit-save-efer", + "vmx-exit-save-pat", + "vmx-exit-save-preemption-timer", + "vmx-flexpriority", + "vmx-hlt-exit", + "vmx-ins-outs", + "vmx-intr-exit", + "vmx-invept", + "vmx-invept-all-context", + "vmx-invept-single-context", + "vmx-invept-single-context-noglobals", + "vmx-invlpg-exit", + "vmx-invpcid-exit", + "vmx-invvpid", + "vmx-invvpid-all-context", + "vmx-invvpid-single-addr", + "vmx-io-bitmap", + "vmx-io-exit", + "vmx-monitor-exit", + "vmx-movdr-exit", + "vmx-msr-bitmap", + "vmx-mtf", + "vmx-mwait-exit", + "vmx-nmi-exit", + "vmx-page-walk-4", + "vmx-page-walk-5", + "vmx-pause-exit", + "vmx-ple", + "vmx-pml", + "vmx-posted-intr", + "vmx-preemption-timer", + "vmx-rdpmc-exit", + "vmx-rdrand-exit", + "vmx-rdseed-exit", + "vmx-rdtsc-exit", + "vmx-rdtscp-exit", + "vmx-secondary-ctls", + "vmx-shadow-vmcs", + "vmx-store-lma", + "vmx-true-ctls", + "vmx-tsc-offset", + "vmx-tsc-scaling", + "vmx-unrestricted-guest", + "vmx-vintr-pending", + "vmx-vmfunc", + "vmx-vmwrite-vmexit-fields", + "vmx-vnmi", + "vmx-vnmi-pending", + "vmx-vpid", + "vmx-wbinvd-exit", + "vmx-xsaves", + "vmx-zero-len-inject", + ] + + if feature["type"] != "bool": + return True + + name = feature["name"] + + if name.startswith("x-"): + return True + + if name in ignored_features: + return True + + return False + + +def get_qemu_feature_list(path_to_qemu): + cmd = [ + path_to_qemu, + "-machine", "accel=kvm", + "-cpu", "host", + "-nodefaults", + "-nographic", + "-qmp", + "stdio" + ] + + request = """ + { + "execute": "qmp_capabilities" + } + { + "execute": "qom-list-properties", + "arguments": { + "typename": "max-x86_64-cpu" + }, + "id": "qom-list-properties" + } + { + "execute": "quit" + } + """ + + decoder = json.JSONDecoder() + output = subprocess.check_output(cmd, input=request, text=True) + while output: + obj, idx = decoder.raw_decode(output) + output = output[idx:].strip() + if obj.get("id") != "qom-list-properties": + continue + for feature in obj["return"]: + if ignore_feature(feature): + continue + yield feature["name"] + + +def get_libvirt_feature_list(path_to_featuresfile): + dom = xml.etree.ElementTree.parse(path_to_featuresfile) + for feature in dom.getroot().iter("feature"): + yield feature.get("name") + for alias in feature: + if alias.tag == "alias": + yield alias.get("name") + + +def main(): + parser = argparse.ArgumentParser( + description="Synchronize x86 cpu features from QEMU i386 target.") + parser.add_argument( + "--qemu", + help="TODO", + default="qemu-kvm", + type=str) + parser.add_argument( + "--features", + help="Path to 'src/cpu_map/x86_features.xml' directory in " + "the libvirt repository", + default="x86_features.xml", + type=str) + + args = parser.parse_args() + + qfeatures = get_qemu_feature_list(args.qemu) + lfeatures = list(get_libvirt_feature_list(args.features)) + missing = [f for f in sorted(qfeatures) if f not in lfeatures] + + if missing: + print("The following features were reported by qemu but are " + "unknown to libvirt:") + for feature in missing: + print(" *", feature) + + return len(missing) != 0 + + +if __name__ == "__main__": + exit(main()) -- 2.36.1