mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
x86: script to automatically process featureset information
This script consumes include/public/arch-x86/cpufeatureset.h and generates a single include/asm-x86/cpuid-autogen.h containing all the processed information. It currently generates just FEATURESET_NR_ENTRIES. Future changes will generate more information. Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com> Acked-by: Jan Beulich <jbeulich@suse.com>
This commit is contained in:
1 parent
77a4b826bb
commit
2e2e2ed0d9
4 files changed
+210
-1
No files matched your search
@@ -252,6 +252,7 @@ xen/include/headers.chk
|
||||
xen/include/headers++.chk
|
||||
xen/include/asm
|
||||
xen/include/asm-*/asm-offsets.h
|
||||
xen/include/asm-x86/cpuid-autogen.h
|
||||
xen/include/compat/*
|
||||
xen/include/config/
|
||||
xen/include/generated/
|
||||
|
||||
@@ -117,5 +117,15 @@ headers++.chk: $(PUBLIC_HEADERS) Makefile
|
||||
|
||||
endif
|
||||
|
||||
ifeq ($(XEN_TARGET_ARCH),x86_64)
|
||||
|
||||
$(BASEDIR)/include/asm-x86/cpuid-autogen.h: $(BASEDIR)/include/public/arch-x86/cpufeatureset.h $(BASEDIR)/tools/gen-cpuid.py FORCE
|
||||
$(PYTHON) $(BASEDIR)/tools/gen-cpuid.py -i $^ -o $@.new
|
||||
$(call move-if-changed,$@.new,$@)
|
||||
|
||||
all: $(BASEDIR)/include/asm-x86/cpuid-autogen.h
|
||||
endif
|
||||
|
||||
clean::
|
||||
rm -rf compat headers.chk headers++.chk
|
||||
rm -f $(BASEDIR)/include/asm-x86/cpuid-autogen.h
|
||||
@@ -11,8 +11,9 @@
|
||||
|
||||
#include <xen/const.h>
|
||||
#include <asm/cpufeatureset.h>
|
||||
#include <asm/cpuid-autogen.h>
|
||||
|
||||
#define FSCAPINTS 9
|
||||
#define FSCAPINTS FEATURESET_NR_ENTRIES
|
||||
#define NCAPINTS (FSCAPINTS + 1) /* N 32-bit words worth of info */
|
||||
|
||||
/* Other features, Xen-defined mapping. */
|
||||
|
||||
Executable
+197
@@ -0,0 +1,197 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import sys, os, re
|
||||
|
||||
class Fail(Exception):
|
||||
pass
|
||||
|
||||
class State(object):
|
||||
|
||||
def __init__(self, input, output):
|
||||
|
||||
self.source = input
|
||||
self.input = open_file_or_fd(input, "r", 2)
|
||||
self.output = open_file_or_fd(output, "w", 2)
|
||||
|
||||
# State parsed from input
|
||||
self.names = {} # Name => value mapping
|
||||
|
||||
# State calculated
|
||||
self.nr_entries = 0 # Number of words in a featureset
|
||||
|
||||
def parse_definitions(state):
|
||||
"""
|
||||
Parse featureset information from @param f and mutate the global
|
||||
namespace with symbols
|
||||
"""
|
||||
feat_regex = re.compile(
|
||||
r"^XEN_CPUFEATURE\(([A-Z0-9_]+),"
|
||||
"\s+([\s\d]+\*[\s\d]+\+[\s\d]+)\).*$")
|
||||
|
||||
this = sys.modules[__name__]
|
||||
|
||||
for l in state.input.readlines():
|
||||
# Short circuit the regex...
|
||||
if not l.startswith("XEN_CPUFEATURE("):
|
||||
continue
|
||||
|
||||
res = feat_regex.match(l)
|
||||
|
||||
if res is None:
|
||||
raise Fail("Failed to interpret '%s'" % (l.strip(), ))
|
||||
|
||||
name = res.groups()[0]
|
||||
val = eval(res.groups()[1]) # Regex confines this to a very simple expression
|
||||
|
||||
if hasattr(this, name):
|
||||
raise Fail("Duplicate symbol %s" % (name,))
|
||||
|
||||
if val in state.names:
|
||||
raise Fail("Aliased value between %s and %s" %
|
||||
(name, state.names[val]))
|
||||
|
||||
# Mutate the current namespace to insert a feature literal with its
|
||||
# bit index. Prepend an underscore if the name starts with a digit.
|
||||
if name[0] in "0123456789":
|
||||
this_name = "_" + name
|
||||
else:
|
||||
this_name = name
|
||||
setattr(this, this_name, val)
|
||||
|
||||
# Construct a reverse mapping of value to name
|
||||
state.names[val] = name
|
||||
|
||||
if len(state.names) == 0:
|
||||
raise Fail("No features found")
|
||||
|
||||
def featureset_to_uint32s(fs, nr):
|
||||
""" Represent a featureset as a list of C-compatible uint32_t's """
|
||||
|
||||
bitmap = 0L
|
||||
for f in fs:
|
||||
bitmap |= 1L << f
|
||||
|
||||
words = []
|
||||
while bitmap:
|
||||
words.append(bitmap & ((1L << 32) - 1))
|
||||
bitmap >>= 32
|
||||
|
||||
assert len(words) <= nr
|
||||
|
||||
if len(words) < nr:
|
||||
words.extend([0] * (nr - len(words)))
|
||||
|
||||
return [ "0x%08xU" % x for x in words ]
|
||||
|
||||
def format_uint32s(words, indent):
|
||||
""" Format a list of uint32_t's suitable for a macro definition """
|
||||
spaces = " " * indent
|
||||
return spaces + (", \\\n" + spaces).join(words) + ", \\"
|
||||
|
||||
|
||||
def crunch_numbers(state):
|
||||
|
||||
# Size of bitmaps
|
||||
state.nr_entries = nr_entries = (max(state.names.keys()) >> 5) + 1
|
||||
|
||||
|
||||
def write_results(state):
|
||||
state.output.write(
|
||||
"""/*
|
||||
* Automatically generated by %s - Do not edit!
|
||||
* Source data: %s
|
||||
*/
|
||||
#ifndef __XEN_X86__FEATURESET_DATA__
|
||||
#define __XEN_X86__FEATURESET_DATA__
|
||||
""" % (sys.argv[0], state.source))
|
||||
|
||||
state.output.write(
|
||||
"""
|
||||
#define FEATURESET_NR_ENTRIES %sU
|
||||
""" % (state.nr_entries,
|
||||
))
|
||||
|
||||
state.output.write(
|
||||
"""
|
||||
#endif /* __XEN_X86__FEATURESET_DATA__ */
|
||||
""")
|
||||
|
||||
|
||||
def open_file_or_fd(val, mode, buffering):
|
||||
"""
|
||||
If 'val' looks like a decimal integer, open it as an fd. If not, try to
|
||||
open it as a regular file.
|
||||
"""
|
||||
|
||||
fd = -1
|
||||
try:
|
||||
# Does it look like an integer?
|
||||
try:
|
||||
fd = int(val, 10)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
if fd == 0:
|
||||
return sys.stdin
|
||||
elif fd == 1:
|
||||
return sys.stdout
|
||||
elif fd == 2:
|
||||
return sys.stderr
|
||||
|
||||
# Try to open it...
|
||||
if fd != -1:
|
||||
return os.fdopen(fd, mode, buffering)
|
||||
else:
|
||||
return open(val, mode, buffering)
|
||||
|
||||
except StandardError, e:
|
||||
if fd != -1:
|
||||
raise Fail("Unable to open fd %d: %s: %s" %
|
||||
(fd, e.__class__.__name__, e))
|
||||
else:
|
||||
raise Fail("Unable to open file '%s': %s: %s" %
|
||||
(val, e.__class__.__name__, e))
|
||||
|
||||
raise SystemExit(2)
|
||||
|
||||
def main():
|
||||
from optparse import OptionParser
|
||||
|
||||
# Change stdout to be line-buffered.
|
||||
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 1)
|
||||
|
||||
parser = OptionParser(usage = "%prog [options] -i INPUT -o OUTPUT",
|
||||
description =
|
||||
"Process featureset information")
|
||||
|
||||
parser.add_option("-i", "--in", dest = "fin", metavar = "<FD or FILE>",
|
||||
default = "0",
|
||||
help = "Featureset definitions")
|
||||
parser.add_option("-o", "--out", dest = "fout", metavar = "<FD or FILE>",
|
||||
default = "1",
|
||||
help = "Featureset calculated information")
|
||||
|
||||
opts, _ = parser.parse_args()
|
||||
|
||||
if opts.fin is None or opts.fout is None:
|
||||
parser.print_help(sys.stderr)
|
||||
raise SystemExit(1)
|
||||
|
||||
state = State(opts.fin, opts.fout)
|
||||
|
||||
parse_definitions(state)
|
||||
crunch_numbers(state)
|
||||
write_results(state)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
sys.exit(main())
|
||||
except Fail, e:
|
||||
print >>sys.stderr, "%s:" % (sys.argv[0],), e
|
||||
sys.exit(1)
|
||||
except SystemExit, e:
|
||||
sys.exit(e.code)
|
||||
except KeyboardInterrupt:
|
||||
sys.exit(2)
|
||||