From patchwork Mon Jul 4 01:14:02 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Monjalon X-Patchwork-Id: 14510 Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [IPv6:::1]) by dpdk.org (Postfix) with ESMTP id E8E964B79; Mon, 4 Jul 2016 03:14:19 +0200 (CEST) Received: from mail-wm0-f45.google.com (mail-wm0-f45.google.com [74.125.82.45]) by dpdk.org (Postfix) with ESMTP id 7FA7347CE for ; Mon, 4 Jul 2016 03:14:18 +0200 (CEST) Received: by mail-wm0-f45.google.com with SMTP id z126so24032733wme.0 for ; Sun, 03 Jul 2016 18:14:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=6wind-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=JYAvWrcJJcLG/3z+egtkG8epFTV6sQh77GeSGGOvo6g=; b=x6KlNaxeB05uk3vUwGP7XhFWONTxf9DFxXALr/NXyusn0iMVUFjDhMw28LLmLyDbCy Y0qtvnZJeb3Rs31HOFV/889+a3mEg8PLRv3LaSBDwvLSgtfHxh39MORgCAZt96E1U4D0 uWg+iXPh4ot6uZo1psDz422TsuzdCb0VjYh9/lRc2Ddp4jHYjlTwTt57INtQlwj5OhiI xU52hobD7+vc/A/dxGWfK+GWPsRgVHZI9qzKhJm+AKTCNpT5i+mb1QtmrSOj8AXT2eIl /kHZXCg6hyj6o+ylBC6w3VgqeA6dzFHvepIyUC4AvvD7MEdiPulg4YdNa8k6d3X2SRkO kSAw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=JYAvWrcJJcLG/3z+egtkG8epFTV6sQh77GeSGGOvo6g=; b=I7fvdxxN9StAND1KSnf8JxNPGY7DruBYZ4GeoZBy8vJ5kDCc0VXLnM98Ba2caJlNkY goNTdImsHo9VFUYiDs8Ikt7jAO0gkEJm13aKESCg546FjnMdzrjtWWJdOy6Aq3cF5yGz fnT3Oi/S9/sChOJ+yrife0P9vYEO0bbJziNKG3reFZ+cPSAp+gPu6aM5nLUCpba1Ght1 Tz5KciAXUoBixtAbprpsQK9RCZdtJJ8ax7f0UwlnTUKEPjQ5CcEj3FY6hzoci/aR3N8z P2bx4R+ClShlbSou7QgFzRJZ6Os/qyTuFJcJSOwwx8sg98ulSG0m01nuHRNk2N4sO7du cGmA== X-Gm-Message-State: ALyK8tKytqbdZ213BuHGk82jqDys89DC+17S/n63mWIMgfpNvQdNYLbudjvsRI8SWzDKKesw X-Received: by 10.194.117.74 with SMTP id kc10mr3701981wjb.126.1467594858031; Sun, 03 Jul 2016 18:14:18 -0700 (PDT) Received: from XPS13.localdomain (184.203.134.77.rev.sfr.net. [77.134.203.184]) by smtp.gmail.com with ESMTPSA id l4sm5527127wjk.18.2016.07.03.18.14.16 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sun, 03 Jul 2016 18:14:17 -0700 (PDT) From: Thomas Monjalon To: Neil Horman Cc: dev@dpdk.org, Panu Matilainen Date: Mon, 4 Jul 2016 03:14:02 +0200 Message-Id: <1467594845-3487-5-git-send-email-thomas.monjalon@6wind.com> X-Mailer: git-send-email 2.7.0 In-Reply-To: <1467594845-3487-1-git-send-email-thomas.monjalon@6wind.com> References: <1466189185-21952-1-git-send-email-nhorman@tuxdriver.com> <1467594845-3487-1-git-send-email-thomas.monjalon@6wind.com> Subject: [dpdk-dev] [PATCH v9 4/7] pmdinfogen: parse driver to generate code to export X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: patches and discussions about DPDK List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Neil Horman dpdk-pmdinfogen is a tool used to parse object files and build JSON strings for use in later determining hardware support in a DSO or application binary. dpdk-pmdinfogen looks for the non-exported symbol names rte_pmd_name (where n is a integer counter) and _pci_table_export. It records the name of each of these tuples, using the later to find the symbolic name of the PCI table for physical devices that the object supports. With this information, it outputs a C file with a single line of the form: static char *_pmd_info[] __attribute__((used)) = " \ PMD_INFO_STRING="; Where is the arbitrary name of the PMD, and is the JSON encoded string that hold relevant PMD information, including the PMD name, type and optional array of PCI device/vendor IDs that the driver supports. This C file is suitable for compiling to object code, then relocatably linking into the parent file from which the C was generated. This creates an entry in the string table of the object that can inform a later tool about hardware support. Note 1: When installed as part of a SDK package, dpdk-pmdinfogen should be built for the SDK target. It is not handled currently. Note 2: Some generated files are not cleaned by "make clean". Signed-off-by: Neil Horman Acked-by: Panu Matilainen Acked-by: Remy Horton Signed-off-by: Thomas Monjalon --- GNUmakefile | 2 +- MAINTAINERS | 4 + GNUmakefile => buildtools/Makefile | 17 +- GNUmakefile => buildtools/pmdinfogen/Makefile | 21 +- buildtools/pmdinfogen/pmdinfogen.c | 451 +++++++++++++++++++++++++ buildtools/pmdinfogen/pmdinfogen.h | 99 ++++++ doc/guides/prog_guide/dev_kit_build_system.rst | 15 +- mk/rte.sdkbuild.mk | 2 +- mk/rte.sdkinstall.mk | 3 + 9 files changed, 587 insertions(+), 27 deletions(-) copy GNUmakefile => buildtools/Makefile (87%) copy GNUmakefile => buildtools/pmdinfogen/Makefile (84%) create mode 100644 buildtools/pmdinfogen/pmdinfogen.c create mode 100644 buildtools/pmdinfogen/pmdinfogen.h diff --git a/GNUmakefile b/GNUmakefile index b59e4b6..00fe0db 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -40,6 +40,6 @@ export RTE_SDK # directory list # -ROOTDIRS-y := lib drivers app +ROOTDIRS-y := buildtools lib drivers app include $(RTE_SDK)/mk/rte.sdkroot.mk diff --git a/MAINTAINERS b/MAINTAINERS index a59191e..1a8a3b7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -68,6 +68,10 @@ F: lib/librte_compat/ F: doc/guides/rel_notes/deprecation.rst F: scripts/validate-abi.sh +Driver information +M: Neil Horman +F: buildtools/pmdinfogen/ + Environment Abstraction Layer ----------------------------- diff --git a/GNUmakefile b/buildtools/Makefile similarity index 87% copy from GNUmakefile copy to buildtools/Makefile index b59e4b6..35a42ff 100644 --- a/GNUmakefile +++ b/buildtools/Makefile @@ -1,6 +1,6 @@ # BSD LICENSE # -# Copyright(c) 2010-2015 Intel Corporation. All rights reserved. +# Copyright(c) 2016 Neil Horman. All rights reserved. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -29,17 +29,8 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# Head Makefile for compiling rte SDK -# - -RTE_SDK := $(CURDIR) -export RTE_SDK - -# -# directory list -# +include $(RTE_SDK)/mk/rte.vars.mk -ROOTDIRS-y := lib drivers app +DIRS-y += pmdinfogen -include $(RTE_SDK)/mk/rte.sdkroot.mk +include $(RTE_SDK)/mk/rte.subdir.mk diff --git a/GNUmakefile b/buildtools/pmdinfogen/Makefile similarity index 84% copy from GNUmakefile copy to buildtools/pmdinfogen/Makefile index b59e4b6..327927e 100644 --- a/GNUmakefile +++ b/buildtools/pmdinfogen/Makefile @@ -1,6 +1,6 @@ # BSD LICENSE # -# Copyright(c) 2010-2015 Intel Corporation. All rights reserved. +# Copyright(c) 2016 Neil Horman. All rights reserved. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -29,17 +29,16 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# Head Makefile for compiling rte SDK -# +include $(RTE_SDK)/mk/rte.vars.mk -RTE_SDK := $(CURDIR) -export RTE_SDK +HOSTAPP_DIR = buildtools +HOSTAPP = dpdk-pmdinfogen -# -# directory list -# +SRCS-y += pmdinfogen.c + +HOST_CFLAGS += $(WERROR_FLAGS) -g +HOST_CFLAGS += -I$(RTE_OUTPUT)/include -ROOTDIRS-y := lib drivers app +DEPDIRS-y += lib/librte_eal -include $(RTE_SDK)/mk/rte.sdkroot.mk +include $(RTE_SDK)/mk/rte.hostapp.mk diff --git a/buildtools/pmdinfogen/pmdinfogen.c b/buildtools/pmdinfogen/pmdinfogen.c new file mode 100644 index 0000000..101bce1 --- /dev/null +++ b/buildtools/pmdinfogen/pmdinfogen.c @@ -0,0 +1,451 @@ +/* Postprocess pmd object files to export hw support + * + * Copyright 2016 Neil Horman + * Based in part on modpost.c from the linux kernel + * + * This software may be used and distributed according to the terms + * of the GNU General Public License V2, incorporated herein by reference. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include "pmdinfogen.h" + +#ifdef RTE_ARCH_64 +#define ADDR_SIZE 64 +#else +#define ADDR_SIZE 32 +#endif + + +static void * +grab_file(const char *filename, unsigned long *size) +{ + struct stat st; + void *map = MAP_FAILED; + int fd; + + fd = open(filename, O_RDONLY); + if (fd < 0) + return NULL; + if (fstat(fd, &st)) + goto failed; + + *size = st.st_size; + map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); + +failed: + close(fd); + if (map == MAP_FAILED) + return NULL; + return map; +} + +/* + * Return a copy of the next line in a mmap'ed file. + * spaces in the beginning of the line is trimmed away. + * Return a pointer to a static buffer. + */ +static void +release_file(void *file, unsigned long size) +{ + munmap(file, size); +} + +/* + * Note, it seems odd that we have both a CONVERT_NATIVE and a TO_NATIVE macro + * below. We do this because the values passed to TO_NATIVE may themselves be + * macros and need both macros here to get expanded. Specifically its the width + * variable we are concerned with, because it needs to get expanded prior to + * string concatenation + */ +#define CONVERT_NATIVE(fend, width, x) ({ \ +typeof(x) ___x; \ +if ((fend) == ELFDATA2LSB) \ + ___x = rte_le_to_cpu_##width(x); \ +else \ + ___x = rte_be_to_cpu_##width(x); \ + ___x; \ +}) + +#define TO_NATIVE(fend, width, x) CONVERT_NATIVE(fend, width, x) + +static int +parse_elf(struct elf_info *info, const char *filename) +{ + unsigned int i; + Elf_Ehdr *hdr; + Elf_Shdr *sechdrs; + Elf_Sym *sym; + int endian; + unsigned int symtab_idx = ~0U, symtab_shndx_idx = ~0U; + + hdr = grab_file(filename, &info->size); + if (!hdr) { + perror(filename); + return -ENOENT; + } + info->hdr = hdr; + if (info->size < sizeof(*hdr)) { + /* file too small, assume this is an empty .o file */ + return 0; + } + /* Is this a valid ELF file? */ + if ((hdr->e_ident[EI_MAG0] != ELFMAG0) || + (hdr->e_ident[EI_MAG1] != ELFMAG1) || + (hdr->e_ident[EI_MAG2] != ELFMAG2) || + (hdr->e_ident[EI_MAG3] != ELFMAG3)) { + /* Not an ELF file - silently ignore it */ + return 0; + } + + if (!hdr->e_ident[EI_DATA]) { + /* Unknown endian */ + return 0; + } + + endian = hdr->e_ident[EI_DATA]; + + /* Fix endianness in ELF header */ + hdr->e_type = TO_NATIVE(endian, 16, hdr->e_type); + hdr->e_machine = TO_NATIVE(endian, 16, hdr->e_machine); + hdr->e_version = TO_NATIVE(endian, 32, hdr->e_version); + hdr->e_entry = TO_NATIVE(endian, ADDR_SIZE, hdr->e_entry); + hdr->e_phoff = TO_NATIVE(endian, ADDR_SIZE, hdr->e_phoff); + hdr->e_shoff = TO_NATIVE(endian, ADDR_SIZE, hdr->e_shoff); + hdr->e_flags = TO_NATIVE(endian, 32, hdr->e_flags); + hdr->e_ehsize = TO_NATIVE(endian, 16, hdr->e_ehsize); + hdr->e_phentsize = TO_NATIVE(endian, 16, hdr->e_phentsize); + hdr->e_phnum = TO_NATIVE(endian, 16, hdr->e_phnum); + hdr->e_shentsize = TO_NATIVE(endian, 16, hdr->e_shentsize); + hdr->e_shnum = TO_NATIVE(endian, 16, hdr->e_shnum); + hdr->e_shstrndx = TO_NATIVE(endian, 16, hdr->e_shstrndx); + + sechdrs = RTE_PTR_ADD(hdr, hdr->e_shoff); + info->sechdrs = sechdrs; + + /* Check if file offset is correct */ + if (hdr->e_shoff > info->size) { + fprintf(stderr, "section header offset=%lu in file '%s' " + "is bigger than filesize=%lu\n", + (unsigned long)hdr->e_shoff, + filename, info->size); + return 0; + } + + if (hdr->e_shnum == SHN_UNDEF) { + /* + * There are more than 64k sections, + * read count from .sh_size. + */ + info->num_sections = TO_NATIVE(endian, 32, sechdrs[0].sh_size); + } else { + info->num_sections = hdr->e_shnum; + } + if (hdr->e_shstrndx == SHN_XINDEX) + info->secindex_strings = + TO_NATIVE(endian, 32, sechdrs[0].sh_link); + else + info->secindex_strings = hdr->e_shstrndx; + + /* Fix endianness in section headers */ + for (i = 0; i < info->num_sections; i++) { + sechdrs[i].sh_name = + TO_NATIVE(endian, 32, sechdrs[i].sh_name); + sechdrs[i].sh_type = + TO_NATIVE(endian, 32, sechdrs[i].sh_type); + sechdrs[i].sh_flags = + TO_NATIVE(endian, 32, sechdrs[i].sh_flags); + sechdrs[i].sh_addr = + TO_NATIVE(endian, ADDR_SIZE, sechdrs[i].sh_addr); + sechdrs[i].sh_offset = + TO_NATIVE(endian, ADDR_SIZE, sechdrs[i].sh_offset); + sechdrs[i].sh_size = + TO_NATIVE(endian, 32, sechdrs[i].sh_size); + sechdrs[i].sh_link = + TO_NATIVE(endian, 32, sechdrs[i].sh_link); + sechdrs[i].sh_info = + TO_NATIVE(endian, 32, sechdrs[i].sh_info); + sechdrs[i].sh_addralign = + TO_NATIVE(endian, ADDR_SIZE, sechdrs[i].sh_addralign); + sechdrs[i].sh_entsize = + TO_NATIVE(endian, ADDR_SIZE, sechdrs[i].sh_entsize); + } + /* Find symbol table. */ + for (i = 1; i < info->num_sections; i++) { + int nobits = sechdrs[i].sh_type == SHT_NOBITS; + + if (!nobits && sechdrs[i].sh_offset > info->size) { + fprintf(stderr, "%s is truncated. " + "sechdrs[i].sh_offset=%lu > sizeof(*hrd)=%zu\n", + filename, (unsigned long)sechdrs[i].sh_offset, + sizeof(*hdr)); + return 0; + } + + if (sechdrs[i].sh_type == SHT_SYMTAB) { + unsigned int sh_link_idx; + symtab_idx = i; + info->symtab_start = RTE_PTR_ADD(hdr, + sechdrs[i].sh_offset); + info->symtab_stop = RTE_PTR_ADD(hdr, + sechdrs[i].sh_offset + sechdrs[i].sh_size); + sh_link_idx = sechdrs[i].sh_link; + info->strtab = RTE_PTR_ADD(hdr, + sechdrs[sh_link_idx].sh_offset); + } + + /* 32bit section no. table? ("more than 64k sections") */ + if (sechdrs[i].sh_type == SHT_SYMTAB_SHNDX) { + symtab_shndx_idx = i; + info->symtab_shndx_start = RTE_PTR_ADD(hdr, + sechdrs[i].sh_offset); + info->symtab_shndx_stop = RTE_PTR_ADD(hdr, + sechdrs[i].sh_offset + sechdrs[i].sh_size); + } + } + if (!info->symtab_start) + fprintf(stderr, "%s has no symtab?\n", filename); + + /* Fix endianness in symbols */ + for (sym = info->symtab_start; sym < info->symtab_stop; sym++) { + sym->st_shndx = TO_NATIVE(endian, 16, sym->st_shndx); + sym->st_name = TO_NATIVE(endian, 32, sym->st_name); + sym->st_value = TO_NATIVE(endian, ADDR_SIZE, sym->st_value); + sym->st_size = TO_NATIVE(endian, ADDR_SIZE, sym->st_size); + } + + if (symtab_shndx_idx != ~0U) { + Elf32_Word *p; + if (symtab_idx != sechdrs[symtab_shndx_idx].sh_link) + fprintf(stderr, + "%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\n", + filename, sechdrs[symtab_shndx_idx].sh_link, + symtab_idx); + /* Fix endianness */ + for (p = info->symtab_shndx_start; p < info->symtab_shndx_stop; p++) + *p = TO_NATIVE(endian, 32, *p); + } + + return 1; +} + +static void +parse_elf_finish(struct elf_info *info) +{ + struct pmd_driver *tmp, *idx = info->drivers; + release_file(info->hdr, info->size); + while (idx) { + tmp = idx->next; + free(idx); + idx = tmp; + } +} + +static const char * +get_sym_name(struct elf_info *elf, Elf_Sym *sym) +{ + if (sym) + return elf->strtab + sym->st_name; + else + return "(unknown)"; +} + +static void * +get_sym_value(struct elf_info *info, const Elf_Sym *sym) +{ + return RTE_PTR_ADD(info->hdr, + info->sechdrs[sym->st_shndx].sh_offset + sym->st_value); +} + +static Elf_Sym * +find_sym_in_symtab(struct elf_info *info, const char *name, Elf_Sym *last) +{ + Elf_Sym *idx; + if (last) + idx = last+1; + else + idx = info->symtab_start; + + for (; idx < info->symtab_stop; idx++) { + const char *n = get_sym_name(info, idx); + if (!strncmp(n, name, strlen(name))) + return idx; + } + return NULL; +} + +struct opt_tag { + const char *suffix; + const char *json_id; +}; + +static const struct opt_tag opt_tags[] = { + {"_param_string_export", "params"}, +}; + +static int +complete_pmd_entry(struct elf_info *info, struct pmd_driver *drv) +{ + const char *tname; + int i; + char tmpsymname[128]; + Elf_Sym *tmpsym; + + drv->name = get_sym_value(info, drv->name_sym); + + for (i = 0; i < PMD_OPT_MAX; i++) { + memset(tmpsymname, 0, 128); + sprintf(tmpsymname, "__%s%s", drv->name, opt_tags[i].suffix); + tmpsym = find_sym_in_symtab(info, tmpsymname, NULL); + if (!tmpsym) + continue; + drv->opt_vals[i] = get_sym_value(info, tmpsym); + } + + memset(tmpsymname, 0, 128); + sprintf(tmpsymname, "__%s_pci_table_export", drv->name); + + tmpsym = find_sym_in_symtab(info, tmpsymname, NULL); + + /* + * If this returns NULL, then this is a PMD_VDEV, because + * it has no pci table reference + */ + if (!tmpsym) { + drv->pci_tbl = NULL; + return 0; + } + + tname = get_sym_value(info, tmpsym); + tmpsym = find_sym_in_symtab(info, tname, NULL); + if (!tmpsym) { + fprintf(stderr, "No symbol %s\n", tname); + return -ENOENT; + } + + drv->pci_tbl = (struct rte_pci_id *)get_sym_value(info, tmpsym); + if (!drv->pci_tbl) { + fprintf(stderr, "Failed to get PCI table %s\n", tname); + return -ENOENT; + } + + return 0; +} + +static int +locate_pmd_entries(struct elf_info *info) +{ + Elf_Sym *last = NULL; + struct pmd_driver *new; + + info->drivers = NULL; + + do { + new = calloc(sizeof(struct pmd_driver), 1); + new->name_sym = find_sym_in_symtab(info, "rte_pmd_name", last); + last = new->name_sym; + if (!new->name_sym) + free(new); + else { + if (complete_pmd_entry(info, new)) { + fprintf(stderr, "Failed to complete pmd entry\n"); + free(new); + return -ENOENT; + } else { + new->next = info->drivers; + info->drivers = new; + } + } + } while (last); + + return 0; +} + +static void +output_pmd_info_string(struct elf_info *info, char *outfile) +{ + FILE *ofd; + struct pmd_driver *drv; + struct rte_pci_id *pci_ids; + int idx = 0; + + ofd = fopen(outfile, "w+"); + if (!ofd) { + fprintf(stderr, "Unable to open output file\n"); + return; + } + + drv = info->drivers; + + while (drv) { + fprintf(ofd, "const char %s_pmd_info[] __attribute__((used)) = " + "\"PMD_INFO_STRING= {", + drv->name); + fprintf(ofd, "\\\"name\\\" : \\\"%s\\\", ", drv->name); + + for (idx = 0; idx < PMD_OPT_MAX; idx++) { + if (drv->opt_vals[idx]) + fprintf(ofd, "\\\"%s\\\" : \\\"%s\\\", ", + opt_tags[idx].json_id, + drv->opt_vals[idx]); + } + + pci_ids = drv->pci_tbl; + fprintf(ofd, "\\\"pci_ids\\\" : ["); + + while (pci_ids && pci_ids->device_id) { + fprintf(ofd, "[%d, %d, %d, %d]", + pci_ids->vendor_id, pci_ids->device_id, + pci_ids->subsystem_vendor_id, + pci_ids->subsystem_device_id); + pci_ids++; + if (pci_ids->device_id) + fprintf(ofd, ","); + else + fprintf(ofd, " "); + } + fprintf(ofd, "]}\";"); + drv = drv->next; + } + + fclose(ofd); +} + +int main(int argc, char **argv) +{ + struct elf_info info; + int rc; + + if (argc < 3) { + fprintf(stderr, + "usage: dpdk-pmdinfogen \n"); + exit(127); + } + + rc = parse_elf(&info, argv[1]); + if (rc < 0) + exit(-rc); + + rc = locate_pmd_entries(&info); + if (rc < 0) + goto error; + + if (info.drivers) { + output_pmd_info_string(&info, argv[2]); + rc = 0; + } else { + rc = -1; + fprintf(stderr, "No drivers registered\n"); + } + +error: + parse_elf_finish(&info); + exit(-rc); +} diff --git a/buildtools/pmdinfogen/pmdinfogen.h b/buildtools/pmdinfogen/pmdinfogen.h new file mode 100644 index 0000000..7e57702 --- /dev/null +++ b/buildtools/pmdinfogen/pmdinfogen.h @@ -0,0 +1,99 @@ +/* Postprocess pmd object files to export hw support + * + * Copyright 2016 Neil Horman + * Based in part on modpost.c from the linux kernel + * + * This software may be used and distributed according to the terms + * of the GNU General Public License V2, incorporated herein by reference. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* On BSD-alike OSes elf.h defines these according to host's word size */ +#undef ELF_ST_BIND +#undef ELF_ST_TYPE +#undef ELF_R_SYM +#undef ELF_R_TYPE + +/* + * Define ELF64_* to ELF_*, the latter being defined in both 32 and 64 bit + * flavors in elf.h. This makes our code a bit more generic between arches + * and allows us to support 32 bit code in the future should we ever want to + */ +#ifdef RTE_ARCH_64 +#define Elf_Ehdr Elf64_Ehdr +#define Elf_Shdr Elf64_Shdr +#define Elf_Sym Elf64_Sym +#define Elf_Addr Elf64_Addr +#define Elf_Sword Elf64_Sxword +#define Elf_Section Elf64_Half +#define ELF_ST_BIND ELF64_ST_BIND +#define ELF_ST_TYPE ELF64_ST_TYPE + +#define Elf_Rel Elf64_Rel +#define Elf_Rela Elf64_Rela +#define ELF_R_SYM ELF64_R_SYM +#define ELF_R_TYPE ELF64_R_TYPE +#else +#define Elf_Ehdr Elf32_Ehdr +#define Elf_Shdr Elf32_Shdr +#define Elf_Sym Elf32_Sym +#define Elf_Addr Elf32_Addr +#define Elf_Sword Elf32_Sxword +#define Elf_Section Elf32_Half +#define ELF_ST_BIND ELF32_ST_BIND +#define ELF_ST_TYPE ELF32_ST_TYPE + +#define Elf_Rel Elf32_Rel +#define Elf_Rela Elf32_Rela +#define ELF_R_SYM ELF32_R_SYM +#define ELF_R_TYPE ELF32_R_TYPE +#endif + + +enum opt_params { + PMD_PARAM_STRING = 0, + PMD_OPT_MAX +}; + +struct pmd_driver { + Elf_Sym *name_sym; + const char *name; + struct rte_pci_id *pci_tbl; + struct pmd_driver *next; + + const char *opt_vals[PMD_OPT_MAX]; +}; + +struct elf_info { + unsigned long size; + Elf_Ehdr *hdr; + Elf_Shdr *sechdrs; + Elf_Sym *symtab_start; + Elf_Sym *symtab_stop; + char *strtab; + + /* support for 32bit section numbers */ + + unsigned int num_sections; /* max_secindex + 1 */ + unsigned int secindex_strings; + /* if Nth symbol table entry has .st_shndx = SHN_XINDEX, + * take shndx from symtab_shndx_start[N] instead + */ + Elf32_Word *symtab_shndx_start; + Elf32_Word *symtab_shndx_stop; + + struct pmd_driver *drivers; +}; diff --git a/doc/guides/prog_guide/dev_kit_build_system.rst b/doc/guides/prog_guide/dev_kit_build_system.rst index dedd18a..fa34fe0 100644 --- a/doc/guides/prog_guide/dev_kit_build_system.rst +++ b/doc/guides/prog_guide/dev_kit_build_system.rst @@ -70,7 +70,7 @@ Each build directory contains include files, libraries, and applications: ... ~/DEV/DPDK$ ls i686-native-linuxapp-gcc - app build hostapp include kmod lib Makefile + app build buildtools include kmod lib Makefile ~/DEV/DPDK$ ls i686-native-linuxapp-gcc/app/ @@ -307,6 +307,7 @@ Misc Internally Generated Build Tools ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``dpdk-pmdinfogen`` scans an object (.o) file for various well known symbol names. These well known symbol names are defined by various macros and used to export important information about hardware support and usage for PMD files. For instance the macro: @@ -321,6 +322,18 @@ Creates the following symbol: static char rte_pmd_name0[] __attribute__((used)) = ""; +Which dpdk-pmdinfogen scans for. Using this information other relevant bits of +data can be exported from the object file and used to produce a hardware support +description, that dpdk-pmdinfogen then encodes into a json formatted string in +the following format: + +.. code-block:: C + + static char ="PMD_INFO_STRING=\"{'name' : '', ...}\""; + +These strings can then be searched for by external tools to determine the +hardware support of a given library or application. + .. _Useful_Variables_Provided_by_the_Build_System: Useful Variables Provided by the Build System diff --git a/mk/rte.sdkbuild.mk b/mk/rte.sdkbuild.mk index f1a163a..5edbf50 100644 --- a/mk/rte.sdkbuild.mk +++ b/mk/rte.sdkbuild.mk @@ -63,7 +63,7 @@ build: $(ROOTDIRS-y) .PHONY: clean clean: $(CLEANDIRS) @rm -rf $(RTE_OUTPUT)/include $(RTE_OUTPUT)/app \ - $(RTE_OUTPUT)/lib $(RTE_OUTPUT)/kmod + $(RTE_OUTPUT)/lib $(RTE_OUTPUT)/kmod $(RTE_OUTPUT)/buildtools @[ -d $(RTE_OUTPUT)/include ] || mkdir -p $(RTE_OUTPUT)/include @$(RTE_SDK)/scripts/gen-config-h.sh $(RTE_OUTPUT)/.config \ > $(RTE_OUTPUT)/include/rte_config.h diff --git a/mk/rte.sdkinstall.mk b/mk/rte.sdkinstall.mk index abdab0f..2b92157 100644 --- a/mk/rte.sdkinstall.mk +++ b/mk/rte.sdkinstall.mk @@ -141,10 +141,13 @@ install-sdk: $(Q)$(call rte_mkdir, $(DESTDIR)$(sdkdir)) $(Q)cp -a $(RTE_SDK)/mk $(DESTDIR)$(sdkdir) $(Q)cp -a $(RTE_SDK)/scripts $(DESTDIR)$(sdkdir) + $(Q)cp -a $O/buildtools $(DESTDIR)$(sdkdir) $(Q)$(call rte_mkdir, $(DESTDIR)$(targetdir)) $(Q)cp -a $O/.config $(DESTDIR)$(targetdir) $(Q)$(call rte_symlink, $(DESTDIR)$(includedir), $(DESTDIR)$(targetdir)/include) $(Q)$(call rte_symlink, $(DESTDIR)$(libdir), $(DESTDIR)$(targetdir)/lib) + $(Q)$(call rte_symlink, $(DESTDIR)$(sdkdir)/buildtools, \ + $(DESTDIR)$(targetdir)/buildtools) install-doc: ifneq ($(wildcard $O/doc),)