2019-02-21 22:28:49 +03:00
#!/usr/bin/env python3
2017-02-01 19:48:41 +03:00
2018-01-05 16:35:42 +03:00
import os
2017-02-01 19:48:41 +03:00
import sys
import json
2017-03-16 14:25:30 +03:00
import xmltodict
2017-02-01 19:48:41 +03:00
2019-09-24 15:55:56 +03:00
2019-04-02 20:02:04 +03:00
def checkCPUIDFeature ( cpuData , feature ) :
2019-04-01 20:23:01 +03:00
eax_in = feature [ " eax_in " ]
ecx_in = feature [ " ecx_in " ]
2017-03-15 16:21:48 +03:00
eax = feature [ " eax " ]
ebx = feature [ " ebx " ]
ecx = feature [ " ecx " ]
edx = feature [ " edx " ]
2019-04-02 20:02:04 +03:00
if " cpuid " not in cpuData :
return False
cpuid = cpuData [ " cpuid " ]
2019-04-01 20:23:01 +03:00
if eax_in not in cpuid or ecx_in not in cpuid [ eax_in ] :
2017-03-15 16:21:48 +03:00
return False
2019-04-01 19:26:38 +03:00
2019-04-01 20:23:01 +03:00
leaf = cpuid [ eax_in ] [ ecx_in ]
2019-04-01 19:26:38 +03:00
return ( ( eax > 0 and leaf [ " eax " ] & eax == eax ) or
( ebx > 0 and leaf [ " ebx " ] & ebx == ebx ) or
( ecx > 0 and leaf [ " ecx " ] & ecx == ecx ) or
( edx > 0 and leaf [ " edx " ] & edx == edx ) )
2017-03-15 16:21:48 +03:00
2019-04-01 19:24:05 +03:00
def checkMSRFeature ( cpuData , feature ) :
index = feature [ " index " ]
edx = feature [ " edx " ]
eax = feature [ " eax " ]
if " msr " not in cpuData :
return False
msr = cpuData [ " msr " ]
if index not in msr :
return False
msr = msr [ index ]
return ( ( edx > 0 and msr [ " edx " ] & edx == edx ) or
( eax > 0 and msr [ " eax " ] & eax == eax ) )
2019-04-02 20:02:04 +03:00
def checkFeature ( cpuData , feature ) :
if feature [ " type " ] == " cpuid " :
return checkCPUIDFeature ( cpuData , feature )
2019-04-01 19:24:05 +03:00
if feature [ " type " ] == " msr " :
return checkMSRFeature ( cpuData , feature )
2019-04-02 20:02:04 +03:00
def addCPUIDFeature ( cpuData , feature ) :
if " cpuid " not in cpuData :
cpuData [ " cpuid " ] = { }
cpuid = cpuData [ " cpuid " ]
2019-04-01 20:23:01 +03:00
if feature [ " eax_in " ] not in cpuid :
cpuid [ feature [ " eax_in " ] ] = { }
leaf = cpuid [ feature [ " eax_in " ] ]
2017-03-15 16:29:30 +03:00
2019-04-01 20:23:01 +03:00
if feature [ " ecx_in " ] not in leaf :
leaf [ feature [ " ecx_in " ] ] = { " eax " : 0 , " ebx " : 0 , " ecx " : 0 , " edx " : 0 }
leaf = leaf [ feature [ " ecx_in " ] ]
2017-03-15 16:29:30 +03:00
2017-03-16 14:25:30 +03:00
for reg in [ " eax " , " ebx " , " ecx " , " edx " ] :
leaf [ reg ] | = feature [ reg ]
2019-04-01 19:24:05 +03:00
def addMSRFeature ( cpuData , feature ) :
if " msr " not in cpuData :
cpuData [ " msr " ] = { }
msr = cpuData [ " msr " ]
if feature [ " index " ] not in msr :
msr [ feature [ " index " ] ] = { " edx " : 0 , " eax " : 0 }
msr = msr [ feature [ " index " ] ]
for reg in [ " edx " , " eax " ] :
msr [ reg ] | = feature [ reg ]
2019-04-02 20:02:04 +03:00
def addFeature ( cpuData , feature ) :
if feature [ " type " ] == " cpuid " :
addCPUIDFeature ( cpuData , feature )
2019-04-01 19:24:05 +03:00
elif feature [ " type " ] == " msr " :
addMSRFeature ( cpuData , feature )
2019-04-02 20:02:04 +03:00
2017-03-16 14:25:30 +03:00
def parseQemu ( path , features ) :
2019-04-01 18:06:59 +03:00
cpuData = { }
2017-03-16 14:25:30 +03:00
with open ( path , " r " ) as f :
2017-09-26 22:08:37 +03:00
data , pos = json . JSONDecoder ( ) . raw_decode ( f . read ( ) )
2017-03-16 14:25:30 +03:00
2019-02-21 22:28:49 +03:00
for ( prop , val ) in data [ " return " ] [ " model " ] [ " props " ] . items ( ) :
2017-03-16 14:25:30 +03:00
if val and prop in features :
2019-04-01 18:06:59 +03:00
addFeature ( cpuData , features [ prop ] )
2017-03-16 14:25:30 +03:00
2019-04-01 18:06:59 +03:00
return cpuData
2017-03-16 14:25:30 +03:00
2019-04-01 18:06:59 +03:00
def parseCPUData ( path ) :
cpuData = { }
2019-02-21 22:28:49 +03:00
with open ( path , " rb " ) as f :
2017-03-16 14:25:30 +03:00
data = xmltodict . parse ( f )
for leaf in data [ " cpudata " ] [ " cpuid " ] :
2019-04-02 20:02:04 +03:00
feature = { " type " : " cpuid " }
2019-04-01 20:23:01 +03:00
feature [ " eax_in " ] = int ( leaf [ " @eax_in " ] , 0 )
feature [ " ecx_in " ] = int ( leaf [ " @ecx_in " ] , 0 )
2017-03-16 14:25:30 +03:00
for reg in [ " eax " , " ebx " , " ecx " , " edx " ] :
feature [ reg ] = int ( leaf [ " @ " + reg ] , 0 )
2019-04-01 18:06:59 +03:00
addFeature ( cpuData , feature )
2017-03-16 14:25:30 +03:00
2019-04-01 19:24:05 +03:00
if " msr " in data [ " cpudata " ] :
if not isinstance ( data [ " cpudata " ] [ " msr " ] , list ) :
data [ " cpudata " ] [ " msr " ] = [ data [ " cpudata " ] [ " msr " ] ]
for msr in data [ " cpudata " ] [ " msr " ] :
feature = { " type " : " msr " }
feature [ " index " ] = int ( msr [ " @index " ] , 0 )
feature [ " edx " ] = int ( msr [ " @edx " ] , 0 )
feature [ " eax " ] = int ( msr [ " @eax " ] , 0 )
addFeature ( cpuData , feature )
2019-04-01 18:06:59 +03:00
return cpuData
2017-03-16 14:25:30 +03:00
2019-04-02 20:13:18 +03:00
def parseMapFeature ( fType , data ) :
ret = { " type " : fType }
2018-01-05 16:35:42 +03:00
2019-04-02 20:13:18 +03:00
if fType == " cpuid " :
fields = [ " eax_in " , " ecx_in " , " eax " , " ebx " , " ecx " , " edx " ]
2019-04-01 19:24:05 +03:00
elif fType == " msr " :
fields = [ " index " , " edx " , " eax " ]
2019-04-02 20:13:18 +03:00
for field in fields :
attr = " @ %s " % field
2018-01-05 16:35:42 +03:00
if attr in data :
2019-04-02 20:13:18 +03:00
ret [ field ] = int ( data [ attr ] , 0 )
2018-01-05 16:35:42 +03:00
else :
2019-04-02 20:13:18 +03:00
ret [ field ] = 0
2018-01-05 16:35:42 +03:00
2019-04-02 20:13:18 +03:00
return ret
2018-01-05 16:35:42 +03:00
def parseMap ( ) :
path = os . path . dirname ( sys . argv [ 0 ] )
2019-02-21 22:10:48 +03:00
path = os . path . join ( path , " .. " , " .. " , " src " , " cpu_map " , " x86_features.xml " )
2019-02-21 22:28:49 +03:00
with open ( path , " rb " ) as f :
2018-01-05 16:35:42 +03:00
data = xmltodict . parse ( f )
cpuMap = { }
2019-02-21 22:10:48 +03:00
for feature in data [ " cpus " ] [ " feature " ] :
2019-04-01 19:24:05 +03:00
for fType in [ " cpuid " , " msr " ] :
2019-04-02 20:13:18 +03:00
if fType in feature :
cpuMap [ feature [ " @name " ] ] = parseMapFeature ( fType , feature [ fType ] )
2018-01-05 16:35:42 +03:00
return cpuMap
2019-04-02 20:02:04 +03:00
def formatCPUData ( cpuData , path , comment ) :
2019-02-21 22:28:49 +03:00
print ( path )
2017-03-16 14:25:30 +03:00
with open ( path , " w " ) as f :
f . write ( " <!-- " + comment + " --> \n " )
f . write ( " <cpudata arch= ' x86 ' > \n " )
2019-04-02 20:02:04 +03:00
cpuid = cpuData [ " cpuid " ]
2019-04-01 20:23:01 +03: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 14:25:30 +03: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 09:48:47 +03:00
f . write ( line % (
2019-04-01 20:23:01 +03:00
eax_in , ecx_in ,
2017-03-16 14:25:30 +03:00
leaf [ " eax " ] , leaf [ " ebx " ] , leaf [ " ecx " ] , leaf [ " edx " ] ) )
2019-04-01 19:24:05 +03:00
if " msr " in cpuData :
msr = cpuData [ " msr " ]
for index in sorted ( msr . keys ( ) ) :
f . write ( " <msr index= ' 0x %x ' edx= ' 0x %08x ' eax= ' 0x %08x ' /> \n " % (
index , msr [ index ] [ ' edx ' ] , msr [ index ] [ ' eax ' ] ) )
2017-03-16 14:25:30 +03:00
f . write ( " </cpudata> \n " )
2018-01-05 16:35:42 +03:00
def diff ( cpuMap , path ) :
2017-03-16 14:25:30 +03:00
base = path . replace ( " .json " , " " )
jsonFile = path
2019-04-01 18:06:59 +03:00
cpuDataFile = base + " .xml "
2017-03-16 14:25:30 +03:00
enabledFile = base + " -enabled.xml "
disabledFile = base + " -disabled.xml "
2019-04-01 18:06:59 +03:00
cpuData = parseCPUData ( cpuDataFile )
2018-01-05 16:35:42 +03:00
qemu = parseQemu ( jsonFile , cpuMap )
2017-03-16 14:25:30 +03:00
2019-04-02 20:02:04 +03:00
enabled = { " cpuid " : { } }
disabled = { " cpuid " : { } }
2018-01-05 16:35:42 +03:00
for feature in cpuMap . values ( ) :
2019-04-01 18:06:59 +03:00
if checkFeature ( qemu , feature ) :
addFeature ( enabled , feature )
elif checkFeature ( cpuData , feature ) :
addFeature ( disabled , feature )
2017-03-16 14:25:30 +03:00
2019-04-01 18:06:59 +03:00
formatCPUData ( enabled , enabledFile , " Features enabled by QEMU " )
formatCPUData ( disabled , disabledFile , " Features disabled by QEMU " )
2017-03-16 14:25:30 +03:00
2017-03-15 15:16:37 +03:00
if len ( sys . argv ) < 3 :
2019-04-01 14:19:16 +03:00
print ( " Usage: %s diff json_file... " % sys . argv [ 0 ] )
2017-03-15 15:16:37 +03:00
sys . exit ( 1 )
action = sys . argv [ 1 ]
args = sys . argv [ 2 : ]
2019-04-01 14:19:16 +03:00
if action == " diff " :
2018-01-05 16:35:42 +03:00
cpuMap = parseMap ( )
2017-03-16 14:25:30 +03:00
for path in args :
2018-01-05 16:35:42 +03:00
diff ( cpuMap , path )
2017-03-15 15:16:37 +03:00
else :
2019-02-21 22:28:49 +03:00
print ( " Unknown action: %s " % action )
2017-03-15 15:16:37 +03:00
sys . exit ( 1 )