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