xref: /dpdk/buildtools/pmdinfogen.py (revision 6c4bf8f42432d421ef162135d1e8c353a6ebe6dc)
1*6c4bf8f4SDmitry Kozlyuk#!/usr/bin/env python3
2*6c4bf8f4SDmitry Kozlyuk# SPDX-License-Identifier: BSD-3-Clause
3*6c4bf8f4SDmitry Kozlyuk# Copyright (c) 2016 Neil Horman <nhorman@tuxdriver.com>
4*6c4bf8f4SDmitry Kozlyuk# Copyright (c) 2020 Dmitry Kozlyuk <dmitry.kozliuk@gmail.com>
5*6c4bf8f4SDmitry Kozlyuk
6*6c4bf8f4SDmitry Kozlyukimport argparse
7*6c4bf8f4SDmitry Kozlyukimport ctypes
8*6c4bf8f4SDmitry Kozlyukimport json
9*6c4bf8f4SDmitry Kozlyukimport sys
10*6c4bf8f4SDmitry Kozlyukimport tempfile
11*6c4bf8f4SDmitry Kozlyuk
12*6c4bf8f4SDmitry Kozlyukfrom elftools.elf.elffile import ELFFile
13*6c4bf8f4SDmitry Kozlyukfrom elftools.elf.sections import SymbolTableSection
14*6c4bf8f4SDmitry Kozlyuk
15*6c4bf8f4SDmitry Kozlyuk
16*6c4bf8f4SDmitry Kozlyukclass ELFSymbol:
17*6c4bf8f4SDmitry Kozlyuk    def __init__(self, image, symbol):
18*6c4bf8f4SDmitry Kozlyuk        self._image = image
19*6c4bf8f4SDmitry Kozlyuk        self._symbol = symbol
20*6c4bf8f4SDmitry Kozlyuk
21*6c4bf8f4SDmitry Kozlyuk    @property
22*6c4bf8f4SDmitry Kozlyuk    def size(self):
23*6c4bf8f4SDmitry Kozlyuk        return self._symbol["st_size"]
24*6c4bf8f4SDmitry Kozlyuk
25*6c4bf8f4SDmitry Kozlyuk    @property
26*6c4bf8f4SDmitry Kozlyuk    def value(self):
27*6c4bf8f4SDmitry Kozlyuk        data = self._image.get_section_data(self._symbol["st_shndx"])
28*6c4bf8f4SDmitry Kozlyuk        base = self._symbol["st_value"]
29*6c4bf8f4SDmitry Kozlyuk        return data[base:base + self.size]
30*6c4bf8f4SDmitry Kozlyuk
31*6c4bf8f4SDmitry Kozlyuk    @property
32*6c4bf8f4SDmitry Kozlyuk    def string_value(self):
33*6c4bf8f4SDmitry Kozlyuk        value = self.value
34*6c4bf8f4SDmitry Kozlyuk        return value[:-1].decode() if value else ""
35*6c4bf8f4SDmitry Kozlyuk
36*6c4bf8f4SDmitry Kozlyuk
37*6c4bf8f4SDmitry Kozlyukclass ELFImage:
38*6c4bf8f4SDmitry Kozlyuk    def __init__(self, data):
39*6c4bf8f4SDmitry Kozlyuk        self._image = ELFFile(data)
40*6c4bf8f4SDmitry Kozlyuk        self._symtab = self._image.get_section_by_name(".symtab")
41*6c4bf8f4SDmitry Kozlyuk        if not isinstance(self._symtab, SymbolTableSection):
42*6c4bf8f4SDmitry Kozlyuk            raise Exception(".symtab section is not a symbol table")
43*6c4bf8f4SDmitry Kozlyuk
44*6c4bf8f4SDmitry Kozlyuk    @property
45*6c4bf8f4SDmitry Kozlyuk    def is_big_endian(self):
46*6c4bf8f4SDmitry Kozlyuk        return not self._image.little_endian
47*6c4bf8f4SDmitry Kozlyuk
48*6c4bf8f4SDmitry Kozlyuk    def get_section_data(self, name):
49*6c4bf8f4SDmitry Kozlyuk        return self._image.get_section(name).data()
50*6c4bf8f4SDmitry Kozlyuk
51*6c4bf8f4SDmitry Kozlyuk    def find_by_name(self, name):
52*6c4bf8f4SDmitry Kozlyuk        symbol = self._symtab.get_symbol_by_name(name)
53*6c4bf8f4SDmitry Kozlyuk        return ELFSymbol(self, symbol[0]) if symbol else None
54*6c4bf8f4SDmitry Kozlyuk
55*6c4bf8f4SDmitry Kozlyuk    def find_by_prefix(self, prefix):
56*6c4bf8f4SDmitry Kozlyuk        for i in range(self._symtab.num_symbols()):
57*6c4bf8f4SDmitry Kozlyuk            symbol = self._symtab.get_symbol(i)
58*6c4bf8f4SDmitry Kozlyuk            if symbol.name.startswith(prefix):
59*6c4bf8f4SDmitry Kozlyuk                yield ELFSymbol(self, symbol)
60*6c4bf8f4SDmitry Kozlyuk
61*6c4bf8f4SDmitry Kozlyuk
62*6c4bf8f4SDmitry Kozlyukdef define_rte_pci_id(is_big_endian):
63*6c4bf8f4SDmitry Kozlyuk    base_type = ctypes.LittleEndianStructure
64*6c4bf8f4SDmitry Kozlyuk    if is_big_endian:
65*6c4bf8f4SDmitry Kozlyuk        base_type = ctypes.BigEndianStructure
66*6c4bf8f4SDmitry Kozlyuk
67*6c4bf8f4SDmitry Kozlyuk    class rte_pci_id(base_type):
68*6c4bf8f4SDmitry Kozlyuk        _pack_ = True
69*6c4bf8f4SDmitry Kozlyuk        _fields_ = [
70*6c4bf8f4SDmitry Kozlyuk            ("class_id", ctypes.c_uint32),
71*6c4bf8f4SDmitry Kozlyuk            ("vendor_id", ctypes.c_uint16),
72*6c4bf8f4SDmitry Kozlyuk            ("device_id", ctypes.c_uint16),
73*6c4bf8f4SDmitry Kozlyuk            ("subsystem_vendor_id", ctypes.c_uint16),
74*6c4bf8f4SDmitry Kozlyuk            ("subsystem_device_id", ctypes.c_uint16),
75*6c4bf8f4SDmitry Kozlyuk        ]
76*6c4bf8f4SDmitry Kozlyuk
77*6c4bf8f4SDmitry Kozlyuk    return rte_pci_id
78*6c4bf8f4SDmitry Kozlyuk
79*6c4bf8f4SDmitry Kozlyuk
80*6c4bf8f4SDmitry Kozlyukclass Driver:
81*6c4bf8f4SDmitry Kozlyuk    OPTIONS = [
82*6c4bf8f4SDmitry Kozlyuk        ("params", "_param_string_export"),
83*6c4bf8f4SDmitry Kozlyuk        ("kmod", "_kmod_dep_export"),
84*6c4bf8f4SDmitry Kozlyuk    ]
85*6c4bf8f4SDmitry Kozlyuk
86*6c4bf8f4SDmitry Kozlyuk    def __init__(self, name, options):
87*6c4bf8f4SDmitry Kozlyuk        self.name = name
88*6c4bf8f4SDmitry Kozlyuk        for key, value in options.items():
89*6c4bf8f4SDmitry Kozlyuk            setattr(self, key, value)
90*6c4bf8f4SDmitry Kozlyuk        self.pci_ids = []
91*6c4bf8f4SDmitry Kozlyuk
92*6c4bf8f4SDmitry Kozlyuk    @classmethod
93*6c4bf8f4SDmitry Kozlyuk    def load(cls, image, symbol):
94*6c4bf8f4SDmitry Kozlyuk        name = symbol.string_value
95*6c4bf8f4SDmitry Kozlyuk
96*6c4bf8f4SDmitry Kozlyuk        options = {}
97*6c4bf8f4SDmitry Kozlyuk        for key, suffix in cls.OPTIONS:
98*6c4bf8f4SDmitry Kozlyuk            option_symbol = image.find_by_name("__%s%s" % (name, suffix))
99*6c4bf8f4SDmitry Kozlyuk            if option_symbol:
100*6c4bf8f4SDmitry Kozlyuk                value = option_symbol.string_value
101*6c4bf8f4SDmitry Kozlyuk                options[key] = value
102*6c4bf8f4SDmitry Kozlyuk
103*6c4bf8f4SDmitry Kozlyuk        driver = cls(name, options)
104*6c4bf8f4SDmitry Kozlyuk
105*6c4bf8f4SDmitry Kozlyuk        pci_table_name_symbol = image.find_by_name("__%s_pci_tbl_export" % name)
106*6c4bf8f4SDmitry Kozlyuk        if pci_table_name_symbol:
107*6c4bf8f4SDmitry Kozlyuk            driver.pci_ids = cls._load_pci_ids(image, pci_table_name_symbol)
108*6c4bf8f4SDmitry Kozlyuk
109*6c4bf8f4SDmitry Kozlyuk        return driver
110*6c4bf8f4SDmitry Kozlyuk
111*6c4bf8f4SDmitry Kozlyuk    @staticmethod
112*6c4bf8f4SDmitry Kozlyuk    def _load_pci_ids(image, table_name_symbol):
113*6c4bf8f4SDmitry Kozlyuk        table_name = table_name_symbol.string_value
114*6c4bf8f4SDmitry Kozlyuk        table_symbol = image.find_by_name(table_name)
115*6c4bf8f4SDmitry Kozlyuk        if not table_symbol:
116*6c4bf8f4SDmitry Kozlyuk            raise Exception("PCI table declared but not defined: %d" % table_name)
117*6c4bf8f4SDmitry Kozlyuk
118*6c4bf8f4SDmitry Kozlyuk        rte_pci_id = define_rte_pci_id(image.is_big_endian)
119*6c4bf8f4SDmitry Kozlyuk
120*6c4bf8f4SDmitry Kozlyuk        pci_id_size = ctypes.sizeof(rte_pci_id)
121*6c4bf8f4SDmitry Kozlyuk        pci_ids_desc = rte_pci_id * (table_symbol.size // pci_id_size)
122*6c4bf8f4SDmitry Kozlyuk        pci_ids = pci_ids_desc.from_buffer_copy(table_symbol.value)
123*6c4bf8f4SDmitry Kozlyuk        result = []
124*6c4bf8f4SDmitry Kozlyuk        for pci_id in pci_ids:
125*6c4bf8f4SDmitry Kozlyuk            if not pci_id.device_id:
126*6c4bf8f4SDmitry Kozlyuk                break
127*6c4bf8f4SDmitry Kozlyuk            result.append([
128*6c4bf8f4SDmitry Kozlyuk                pci_id.vendor_id,
129*6c4bf8f4SDmitry Kozlyuk                pci_id.device_id,
130*6c4bf8f4SDmitry Kozlyuk                pci_id.subsystem_vendor_id,
131*6c4bf8f4SDmitry Kozlyuk                pci_id.subsystem_device_id,
132*6c4bf8f4SDmitry Kozlyuk                ])
133*6c4bf8f4SDmitry Kozlyuk        return result
134*6c4bf8f4SDmitry Kozlyuk
135*6c4bf8f4SDmitry Kozlyuk    def dump(self, file):
136*6c4bf8f4SDmitry Kozlyuk        dumped = json.dumps(self.__dict__)
137*6c4bf8f4SDmitry Kozlyuk        escaped = dumped.replace('"', '\\"')
138*6c4bf8f4SDmitry Kozlyuk        print(
139*6c4bf8f4SDmitry Kozlyuk            'const char %s_pmd_info[] __attribute__((used)) = "PMD_INFO_STRING= %s";'
140*6c4bf8f4SDmitry Kozlyuk            % (self.name, escaped),
141*6c4bf8f4SDmitry Kozlyuk            file=file,
142*6c4bf8f4SDmitry Kozlyuk        )
143*6c4bf8f4SDmitry Kozlyuk
144*6c4bf8f4SDmitry Kozlyuk
145*6c4bf8f4SDmitry Kozlyukdef load_drivers(image):
146*6c4bf8f4SDmitry Kozlyuk    drivers = []
147*6c4bf8f4SDmitry Kozlyuk    for symbol in image.find_by_prefix("this_pmd_name"):
148*6c4bf8f4SDmitry Kozlyuk        drivers.append(Driver.load(image, symbol))
149*6c4bf8f4SDmitry Kozlyuk    return drivers
150*6c4bf8f4SDmitry Kozlyuk
151*6c4bf8f4SDmitry Kozlyuk
152*6c4bf8f4SDmitry Kozlyukdef dump_drivers(drivers, file):
153*6c4bf8f4SDmitry Kozlyuk    # Keep legacy order of definitions.
154*6c4bf8f4SDmitry Kozlyuk    for driver in reversed(drivers):
155*6c4bf8f4SDmitry Kozlyuk        driver.dump(file)
156*6c4bf8f4SDmitry Kozlyuk
157*6c4bf8f4SDmitry Kozlyuk
158*6c4bf8f4SDmitry Kozlyukdef parse_args():
159*6c4bf8f4SDmitry Kozlyuk    parser = argparse.ArgumentParser()
160*6c4bf8f4SDmitry Kozlyuk    parser.add_argument("input", help="input object file path or '-' for stdin")
161*6c4bf8f4SDmitry Kozlyuk    parser.add_argument("output", help="output C file path or '-' for stdout")
162*6c4bf8f4SDmitry Kozlyuk    return parser.parse_args()
163*6c4bf8f4SDmitry Kozlyuk
164*6c4bf8f4SDmitry Kozlyuk
165*6c4bf8f4SDmitry Kozlyukdef open_input(path):
166*6c4bf8f4SDmitry Kozlyuk    if path == "-":
167*6c4bf8f4SDmitry Kozlyuk        temp = tempfile.TemporaryFile()
168*6c4bf8f4SDmitry Kozlyuk        temp.write(sys.stdin.buffer.read())
169*6c4bf8f4SDmitry Kozlyuk        return temp
170*6c4bf8f4SDmitry Kozlyuk    return open(path, "rb")
171*6c4bf8f4SDmitry Kozlyuk
172*6c4bf8f4SDmitry Kozlyuk
173*6c4bf8f4SDmitry Kozlyukdef open_output(path):
174*6c4bf8f4SDmitry Kozlyuk    if path == "-":
175*6c4bf8f4SDmitry Kozlyuk        return sys.stdout
176*6c4bf8f4SDmitry Kozlyuk    return open(path, "w")
177*6c4bf8f4SDmitry Kozlyuk
178*6c4bf8f4SDmitry Kozlyuk
179*6c4bf8f4SDmitry Kozlyukdef main():
180*6c4bf8f4SDmitry Kozlyuk    args = parse_args()
181*6c4bf8f4SDmitry Kozlyuk    infile = open_input(args.input)
182*6c4bf8f4SDmitry Kozlyuk    image = ELFImage(infile)
183*6c4bf8f4SDmitry Kozlyuk    drivers = load_drivers(image)
184*6c4bf8f4SDmitry Kozlyuk    output = open_output(args.output)
185*6c4bf8f4SDmitry Kozlyuk    dump_drivers(drivers, output)
186*6c4bf8f4SDmitry Kozlyuk
187*6c4bf8f4SDmitry Kozlyuk
188*6c4bf8f4SDmitry Kozlyukif __name__ == "__main__":
189*6c4bf8f4SDmitry Kozlyuk    main()
190