LCOV - code coverage report
Current view: top level - drivers/net/nfp/nfpcore - nfp_elf.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 0 393 0.0 %
Date: 2024-04-01 19:00:53 Functions: 0 16 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 215 0.0 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  * Copyright (c) 2023 Corigine, Inc.
       3                 :            :  * All rights reserved.
       4                 :            :  */
       5                 :            : 
       6                 :            : #include "nfp_elf.h"
       7                 :            : 
       8                 :            : #include <malloc.h>
       9                 :            : #include <stdbool.h>
      10                 :            : #include <ethdev_pci.h>
      11                 :            : 
      12                 :            : #include <nfp_platform.h>
      13                 :            : #include <rte_common.h>
      14                 :            : #include <eal_firmware.h>
      15                 :            : 
      16                 :            : #include "nfp_logs.h"
      17                 :            : #include "nfp_mip.h"
      18                 :            : 
      19                 :            : /*
      20                 :            :  * NFP Chip Families.
      21                 :            :  *
      22                 :            :  * These are not enums, because they need to be microcode compatible.
      23                 :            :  * They are also not maskable.
      24                 :            :  *
      25                 :            :  * Note: The NFP-4xxx family is handled as NFP-6xxx in most software
      26                 :            :  * components.
      27                 :            :  */
      28                 :            : #define NFP_CHIP_FAMILY_NFP3800 0x3800
      29                 :            : #define NFP_CHIP_FAMILY_NFP6000 0x6000
      30                 :            : 
      31                 :            : /* Standard ELF */
      32                 :            : #define NFP_ELF_EI_NIDENT     16
      33                 :            : #define NFP_ELF_EI_MAG0       0
      34                 :            : #define NFP_ELF_EI_MAG1       1
      35                 :            : #define NFP_ELF_EI_MAG2       2
      36                 :            : #define NFP_ELF_EI_MAG3       3
      37                 :            : #define NFP_ELF_EI_CLASS      4
      38                 :            : #define NFP_ELF_EI_DATA       5
      39                 :            : #define NFP_ELF_EI_VERSION    6
      40                 :            : #define NFP_ELF_EI_PAD        7
      41                 :            : #define NFP_ELF_ELFMAG0       0x7f
      42                 :            : #define NFP_ELF_ELFMAG1       'E'
      43                 :            : #define NFP_ELF_ELFMAG2       'L'
      44                 :            : #define NFP_ELF_ELFMAG3       'F'
      45                 :            : #define NFP_ELF_ELFCLASSNONE  0
      46                 :            : #define NFP_ELF_ELFCLASS32    1
      47                 :            : #define NFP_ELF_ELFCLASS64    2
      48                 :            : #define NFP_ELF_ELFDATANONE   0
      49                 :            : #define NFP_ELF_ELFDATA2LSB   1
      50                 :            : #define NFP_ELF_ELFDATA2MSB   2
      51                 :            : 
      52                 :            : #define NFP_ELF_ET_NONE       0
      53                 :            : #define NFP_ELF_ET_REL        1
      54                 :            : #define NFP_ELF_ET_EXEC       2
      55                 :            : #define NFP_ELF_ET_DYN        3
      56                 :            : #define NFP_ELF_ET_CORE       4
      57                 :            : #define NFP_ELF_ET_LOPROC     0xFF00
      58                 :            : #define NFP_ELF_ET_HIPROC     0xFFFF
      59                 :            : #define NFP_ELF_ET_NFP_PARTIAL_REL   (NFP_ELF_ET_LOPROC + NFP_ELF_ET_REL)
      60                 :            : #define NFP_ELF_ET_NFP_PARTIAL_EXEC  (NFP_ELF_ET_LOPROC + NFP_ELF_ET_EXEC)
      61                 :            : 
      62                 :            : #define NFP_ELF_EM_NFP        250
      63                 :            : #define NFP_ELF_EM_NFP6000    0x6000
      64                 :            : 
      65                 :            : #define NFP_ELF_SHT_NULL      0
      66                 :            : #define NFP_ELF_SHT_PROGBITS  1
      67                 :            : #define NFP_ELF_SHT_SYMTAB    2
      68                 :            : #define NFP_ELF_SHT_STRTAB    3
      69                 :            : #define NFP_ELF_SHT_RELA      4
      70                 :            : #define NFP_ELF_SHT_HASH      5
      71                 :            : #define NFP_ELF_SHT_DYNAMIC   6
      72                 :            : #define NFP_ELF_SHT_NOTE      7
      73                 :            : #define NFP_ELF_SHT_NOBITS    8
      74                 :            : #define NFP_ELF_SHT_REL       9
      75                 :            : #define NFP_ELF_SHT_SHLIB     10
      76                 :            : #define NFP_ELF_SHT_DYNSYM    11
      77                 :            : #define NFP_ELF_SHT_LOPROC    0x70000000
      78                 :            : #define NFP_ELF_SHT_HIPROC    0x7fffffff
      79                 :            : #define NFP_ELF_SHT_LOUSER    0x80000000
      80                 :            : #define NFP_ELF_SHT_HIUSER    0x8fffffff
      81                 :            : 
      82                 :            : #define NFP_ELF_EV_NONE       0
      83                 :            : #define NFP_ELF_EV_CURRENT    1
      84                 :            : 
      85                 :            : #define NFP_ELF_SHN_UNDEF     0
      86                 :            : 
      87                 :            : /* EM_NFP ELF flags */
      88                 :            : 
      89                 :            : /*
      90                 :            :  * Valid values for FAMILY are:
      91                 :            :  * 0x6000 - NFP-6xxx/NFP-4xxx
      92                 :            :  * 0x3800 - NFP-38xx
      93                 :            :  */
      94                 :            : #define NFP_ELF_EF_NFP_FAMILY_MASK        0xFFFF
      95                 :            : #define NFP_ELF_EF_NFP_FAMILY_LSB         8
      96                 :            : 
      97                 :            : #define NFP_ELF_SHT_NFP_MECONFIG          (NFP_ELF_SHT_LOPROC + 1)
      98                 :            : #define NFP_ELF_SHT_NFP_INITREG           (NFP_ELF_SHT_LOPROC + 2)
      99                 :            : #define NFP_ELF_SHT_UOF_DEBUG             (NFP_ELF_SHT_LOUSER)
     100                 :            : 
     101                 :            : /* NFP target revision note type */
     102                 :            : #define NFP_ELT_NOTE_NAME_NFP             "NFP\0"
     103                 :            : #define NFP_ELT_NOTE_NAME_NFP_SZ          4
     104                 :            : #define NFP_ELT_NOTE_NAME_NFP_USER        "NFP_USR\0"
     105                 :            : #define NFP_ELT_NOTE_NAME_NFP_USER_SZ     8
     106                 :            : #define NFP_ELF_NT_NFP_BUILD_INFO         0x100
     107                 :            : #define NFP_ELF_NT_NFP_REVS               0x101
     108                 :            : #define NFP_ELF_NT_NFP_MIP_LOCATION       0x102
     109                 :            : #define NFP_ELF_NT_NFP_USER               0xf0000000
     110                 :            : 
     111                 :            : 
     112                 :            : /* Standard ELF structures */
     113                 :            : struct nfp_elf_elf64_ehdr {
     114                 :            :         uint8_t e_ident[NFP_ELF_EI_NIDENT];
     115                 :            :         rte_le16_t e_type;
     116                 :            :         rte_le16_t e_machine;
     117                 :            :         rte_le32_t e_version;
     118                 :            :         rte_le64_t e_entry;
     119                 :            :         rte_le64_t e_phoff;
     120                 :            :         rte_le64_t e_shoff;
     121                 :            :         rte_le32_t e_flags;
     122                 :            :         rte_le16_t e_ehsize;
     123                 :            :         rte_le16_t e_phentsize;
     124                 :            :         rte_le16_t e_phnum;
     125                 :            :         rte_le16_t e_shentsize;
     126                 :            :         rte_le16_t e_shnum;
     127                 :            :         rte_le16_t e_shstrndx;
     128                 :            : };
     129                 :            : 
     130                 :            : struct nfp_elf_elf64_shdr {
     131                 :            :         rte_le32_t sh_name;
     132                 :            :         rte_le32_t sh_type;
     133                 :            :         rte_le64_t sh_flags;
     134                 :            :         rte_le64_t sh_addr;
     135                 :            :         rte_le64_t sh_offset;
     136                 :            :         rte_le64_t sh_size;
     137                 :            :         rte_le32_t sh_link;
     138                 :            :         rte_le32_t sh_info;
     139                 :            :         rte_le64_t sh_addralign;
     140                 :            :         rte_le64_t sh_entsize;
     141                 :            : };
     142                 :            : 
     143                 :            : struct nfp_elf_elf64_sym {
     144                 :            :         rte_le32_t st_name;
     145                 :            :         uint8_t st_info;
     146                 :            :         uint8_t st_other;
     147                 :            :         rte_le16_t st_shndx;
     148                 :            :         rte_le64_t st_value;
     149                 :            :         rte_le64_t st_size;
     150                 :            : };
     151                 :            : 
     152                 :            : struct nfp_elf_elf64_rel {
     153                 :            :         rte_le64_t r_offset;
     154                 :            :         rte_le64_t r_info;
     155                 :            : };
     156                 :            : 
     157                 :            : struct nfp_elf_elf64_nhdr {
     158                 :            :         rte_le32_t n_namesz;
     159                 :            :         rte_le32_t n_descsz;
     160                 :            :         rte_le32_t n_type;
     161                 :            : };
     162                 :            : 
     163                 :            : /* NFP specific structures */
     164                 :            : struct nfp_elf_elf_meconfig {
     165                 :            :         rte_le32_t ctx_enables;
     166                 :            :         rte_le32_t entry;
     167                 :            :         rte_le32_t misc_control;
     168                 :            :         rte_le32_t reserved;
     169                 :            : };
     170                 :            : 
     171                 :            : struct nfp_elf_elf_initregentry {
     172                 :            :         rte_le32_t w0;
     173                 :            :         rte_le32_t cpp_offset_lo;
     174                 :            :         rte_le32_t val;
     175                 :            :         rte_le32_t mask;
     176                 :            : };
     177                 :            : 
     178                 :            : /* NFP NFFW ELF struct and API */
     179                 :            : struct nfp_elf_user_note {
     180                 :            :         const char *name;
     181                 :            :         uint32_t data_sz;
     182                 :            :         void *data;
     183                 :            : };
     184                 :            : 
     185                 :            : /*
     186                 :            :  * nfp_elf_fw_mip contains firmware related fields from the MIP as well as the
     187                 :            :  * MIP location in the NFFW file. All fields are only valid if shndx > 0.
     188                 :            :  *
     189                 :            :  * This struct will only be available if the firmware contains a .note section
     190                 :            :  * with a note of type NFP_ELF_NT_NFP_MIP_LOCATION.
     191                 :            :  */
     192                 :            : struct nfp_elf_fw_mip {
     193                 :            :         size_t shndx;
     194                 :            :         uint64_t sh_offset;
     195                 :            :         rte_le32_t mip_ver;      /**< Version of the format of the MIP itself */
     196                 :            : 
     197                 :            :         rte_le32_t fw_version;
     198                 :            :         rte_le32_t fw_buildnum;
     199                 :            :         rte_le32_t fw_buildtime;
     200                 :            :         char fw_name[20];        /**< At most 16 chars, 17 ensures '\0', round up */
     201                 :            :         const char *fw_typeid;   /**< NULL if none set */
     202                 :            : };
     203                 :            : 
     204                 :            : /*
     205                 :            :  * It is preferred to access this struct via the nfp_elf functions
     206                 :            :  * rather than directly.
     207                 :            :  */
     208                 :            : struct nfp_elf {
     209                 :            :         struct nfp_elf_elf64_ehdr *ehdr;
     210                 :            :         struct nfp_elf_elf64_shdr *shdrs;
     211                 :            :         size_t shdrs_cnt;
     212                 :            :         void **shdrs_data;
     213                 :            : 
     214                 :            :         /** True if section data has been endian swapped */
     215                 :            :         uint8_t *shdrs_host_endian;
     216                 :            : 
     217                 :            :         size_t shdr_idx_symtab;
     218                 :            : 
     219                 :            :         struct nfp_elf_elf64_sym *syms;
     220                 :            :         size_t syms_cnt;
     221                 :            : 
     222                 :            :         char *shstrtab;
     223                 :            :         size_t shstrtab_sz;
     224                 :            : 
     225                 :            :         char *symstrtab;
     226                 :            :         size_t symstrtab_sz;
     227                 :            : 
     228                 :            :         struct nfp_elf_elf_meconfig *meconfs;
     229                 :            :         size_t meconfs_cnt;
     230                 :            : 
     231                 :            :         /* ==== .note data start ==== */
     232                 :            : 
     233                 :            :         /**
     234                 :            :          * Following data derived from SHT_NOTE sections for read-only usage.
     235                 :            :          * These fields are not used in nfp_elf_to_buf()
     236                 :            :          */
     237                 :            :         int rev_min; /**< -1 if file did not specify */
     238                 :            :         int rev_max; /**< -1 if file did not specify */
     239                 :            : 
     240                 :            :         /**
     241                 :            :          * If mip_shndx == 0 and mip_sh_off == 0, the .note stated there is no MIP.
     242                 :            :          * If mip_shndx == 0 and mip_sh_off == UINT64_MAX, there was no .note and
     243                 :            :          * a MIP _may_ still be found in the first 256KiB of DRAM/EMEM data.
     244                 :            :          */
     245                 :            :         size_t mip_shndx; /**< Section in which MIP resides, 0 if no MIP */
     246                 :            :         uint64_t mip_sh_off; /**< Offset within section (not address) */
     247                 :            : 
     248                 :            :         struct nfp_elf_fw_mip fw_mip;
     249                 :            :         const char *fw_info_strtab;
     250                 :            :         size_t fw_info_strtab_sz;
     251                 :            : 
     252                 :            :         /* ==== .note.user data start ==== */
     253                 :            :         size_t user_note_cnt;
     254                 :            :         struct nfp_elf_user_note *user_notes;
     255                 :            : 
     256                 :            :         void *dbgdata;
     257                 :            : 
     258                 :            :         int family;
     259                 :            : 
     260                 :            :         /**
     261                 :            :          * For const entry points in the API, we allocate and keep a buffer
     262                 :            :          * and for mutable entry points we assume the buffer remains valid
     263                 :            :          * and we just set pointers to it.
     264                 :            :          */
     265                 :            :         void *_buf;
     266                 :            :         size_t _bufsz;
     267                 :            : };
     268                 :            : 
     269                 :            : static void
     270                 :          0 : nfp_elf_free(struct nfp_elf *ectx)
     271                 :            : {
     272         [ #  # ]:          0 :         if (ectx == NULL)
     273                 :            :                 return;
     274                 :            : 
     275                 :          0 :         free(ectx->shdrs);
     276                 :          0 :         free(ectx->shdrs_data);
     277                 :          0 :         free(ectx->shdrs_host_endian);
     278         [ #  # ]:          0 :         if (ectx->_bufsz != 0)
     279                 :          0 :                 free(ectx->_buf);
     280                 :            : 
     281                 :          0 :         free(ectx);
     282                 :            : }
     283                 :            : 
     284                 :            : static size_t
     285                 :            : nfp_elf_get_sec_ent_cnt(struct nfp_elf *ectx,
     286                 :            :                 size_t idx)
     287                 :            : {
     288                 :          0 :         uint64_t sh_size = rte_le_to_cpu_64(ectx->shdrs[idx].sh_size);
     289                 :          0 :         uint64_t sh_entsize = rte_le_to_cpu_64(ectx->shdrs[idx].sh_entsize);
     290                 :            : 
     291                 :          0 :         if (sh_entsize != 0)
     292                 :          0 :                 return sh_size / sh_entsize;
     293                 :            : 
     294                 :            :         return 0;
     295                 :            : }
     296                 :            : 
     297                 :            : static bool
     298                 :            : nfp_elf_check_sh_size(uint64_t sh_size)
     299                 :            : {
     300   [ #  #  #  #  :          0 :         if (sh_size == 0 || sh_size > UINT32_MAX)
             #  #  #  # ]
     301                 :            :                 return false;
     302                 :            : 
     303                 :            :         return true;
     304                 :            : }
     305                 :            : 
     306                 :            : static const char *
     307                 :          0 : nfp_elf_fwinfo_next(struct nfp_elf *ectx,
     308                 :            :                 const char *key_val)
     309                 :            : {
     310                 :            :         size_t s_len;
     311                 :          0 :         const char *strtab = ectx->fw_info_strtab;
     312                 :          0 :         ssize_t tab_sz = (ssize_t)ectx->fw_info_strtab_sz;
     313                 :            : 
     314         [ #  # ]:          0 :         if (key_val == NULL)
     315                 :            :                 return strtab;
     316                 :            : 
     317                 :          0 :         s_len = strlen(key_val);
     318   [ #  #  #  # ]:          0 :         if (key_val < strtab || ((key_val + s_len + 1) >= (strtab + tab_sz - 1)))
     319                 :          0 :                 return NULL;
     320                 :            : 
     321                 :            :         key_val += s_len + 1;
     322                 :            : 
     323                 :            :         return key_val;
     324                 :            : }
     325                 :            : 
     326                 :            : static const char *
     327                 :          0 : nfp_elf_fwinfo_lookup(const char *strtab,
     328                 :            :                 ssize_t tab_sz,
     329                 :            :                 const char *key)
     330                 :            : {
     331                 :            :         size_t s_len;
     332                 :            :         const char *s;
     333                 :          0 :         size_t key_len = strlen(key);
     334                 :            : 
     335         [ #  # ]:          0 :         if (strtab == NULL)
     336                 :            :                 return NULL;
     337                 :            : 
     338                 :            :         for (s = strtab, s_len = strlen(s) + 1;
     339   [ #  #  #  # ]:          0 :                         (s[0] != '\0') && (tab_sz > 0);
     340                 :          0 :                         s_len = strlen(s) + 1, tab_sz -= s_len, s += s_len) {
     341   [ #  #  #  # ]:          0 :                 if ((strncmp(s, key, key_len) == 0) && (s[key_len] == '='))
     342                 :          0 :                         return &s[key_len + 1];
     343                 :            :         }
     344                 :            : 
     345                 :            :         return NULL;
     346                 :            : }
     347                 :            : 
     348                 :            : static bool
     349                 :            : nfp_elf_arch_is_thornham(struct nfp_elf *ectx)
     350                 :            : {
     351                 :          0 :         if (ectx == NULL)
     352                 :            :                 return false;
     353                 :            : 
     354         [ #  # ]:          0 :         if (ectx->family == NFP_CHIP_FAMILY_NFP6000 || ectx->family == NFP_CHIP_FAMILY_NFP3800)
     355                 :            :                 return true;
     356                 :            : 
     357                 :            :         return false;
     358                 :            : }
     359                 :            : 
     360                 :            : static int
     361                 :          0 : nfp_elf_parse_sht_rel(struct nfp_elf_elf64_shdr *sec,
     362                 :            :                 struct nfp_elf *ectx,
     363                 :            :                 size_t idx,
     364                 :            :                 uint8_t *buf8)
     365                 :            : {
     366                 :          0 :         uint64_t sh_size = rte_le_to_cpu_64(sec->sh_size);
     367                 :          0 :         uint64_t sh_offset = rte_le_to_cpu_64(sec->sh_offset);
     368                 :          0 :         uint64_t sh_entsize = rte_le_to_cpu_64(sec->sh_entsize);
     369                 :            : 
     370         [ #  # ]:          0 :         if (sh_entsize != sizeof(struct nfp_elf_elf64_rel)) {
     371                 :          0 :                 PMD_DRV_LOG(ERR, "Invalid ELF section header, index %zu.", idx);
     372                 :          0 :                 return -EINVAL;
     373                 :            :         }
     374                 :            : 
     375                 :            :         if (!nfp_elf_check_sh_size(sh_size)) {
     376                 :          0 :                 PMD_DRV_LOG(ERR, "Invalid ELF section header, index %zu.", idx);
     377                 :          0 :                 return -EINVAL;
     378                 :            :         }
     379                 :            : 
     380                 :          0 :         ectx->shdrs_data[idx] = buf8 + sh_offset;
     381                 :          0 :         ectx->shdrs_host_endian[idx] = 1;
     382                 :            : 
     383                 :          0 :         return 0;
     384                 :            : }
     385                 :            : 
     386                 :            : static int
     387                 :          0 : nfp_elf_parse_note_name_nfp(struct nfp_elf *ectx,
     388                 :            :                 size_t idx,
     389                 :            :                 uint32_t ndescsz,
     390                 :            :                 uint32_t ntype,
     391                 :            :                 const char *nname,
     392                 :            :                 rte_le32_t *descword)
     393                 :            : {
     394         [ #  # ]:          0 :         if (strncmp(nname, NFP_ELT_NOTE_NAME_NFP, NFP_ELT_NOTE_NAME_NFP_SZ) == 0) {
     395      [ #  #  # ]:          0 :                 switch (ntype) {
     396                 :          0 :                 case NFP_ELF_NT_NFP_REVS:
     397         [ #  # ]:          0 :                         if (ndescsz != 8) {
     398                 :          0 :                                 PMD_DRV_LOG(ERR, "Invalid ELF NOTE descsz in section %zu.", idx);
     399                 :          0 :                                 return -EINVAL;
     400                 :            :                         }
     401                 :            : 
     402                 :          0 :                         ectx->rev_min = (int)rte_le_to_cpu_32(descword[0]);
     403                 :          0 :                         ectx->rev_max = (int)rte_le_to_cpu_32(descword[1]);
     404                 :          0 :                         break;
     405                 :          0 :                 case NFP_ELF_NT_NFP_MIP_LOCATION:
     406         [ #  # ]:          0 :                         if (ndescsz != 12) {
     407                 :          0 :                                 PMD_DRV_LOG(ERR, "Invalid ELF NOTE descsz in section %zu.", idx);
     408                 :          0 :                                 return -EINVAL;
     409                 :            :                         }
     410                 :            : 
     411                 :          0 :                         ectx->mip_shndx = rte_le_to_cpu_32(descword[0]);
     412         [ #  # ]:          0 :                         if (ectx->mip_shndx == 0) {
     413                 :          0 :                                 ectx->mip_sh_off = 0;
     414                 :          0 :                                 break;
     415                 :            :                         }
     416                 :            : 
     417         [ #  # ]:          0 :                         if (ectx->mip_shndx >= ectx->shdrs_cnt) {
     418                 :          0 :                                 PMD_DRV_LOG(ERR, "Invalid ELF NOTE shndx in section %zu.", idx);
     419                 :          0 :                                 return -EINVAL;
     420                 :            :                         }
     421                 :            : 
     422                 :          0 :                         ectx->mip_sh_off = rte_le_to_cpu_32(descword[1]) |
     423                 :          0 :                                         (uint64_t)rte_le_to_cpu_32(descword[2]) << 32;
     424                 :          0 :                         break;
     425                 :            :                 default:
     426                 :            :                         break;
     427                 :            :                 }
     428         [ #  # ]:          0 :         } else if (strncmp(nname, NFP_ELT_NOTE_NAME_NFP_USER,
     429         [ #  # ]:          0 :                         NFP_ELT_NOTE_NAME_NFP_USER_SZ) == 0 && ntype == NFP_ELF_NT_NFP_USER) {
     430                 :          0 :                 ectx->user_note_cnt++;
     431                 :            :         }
     432                 :            : 
     433                 :            :         return 0;
     434                 :            : }
     435                 :            : 
     436                 :            : static int
     437                 :          0 : nfp_elf_parse_sht_note(struct nfp_elf_elf64_shdr *sec,
     438                 :            :                 struct nfp_elf *ectx,
     439                 :            :                 size_t idx,
     440                 :            :                 uint8_t *buf8)
     441                 :            : {
     442                 :            :         int err;
     443                 :            :         size_t nsz;
     444                 :            :         uint8_t *desc;
     445                 :            :         uint32_t ntype;
     446                 :            :         uint32_t nnamesz;
     447                 :            :         uint32_t ndescsz;
     448                 :            :         const char *nname;
     449                 :            :         uint8_t *shdrs_data;
     450                 :            :         rte_le32_t *descword;
     451                 :            :         struct nfp_elf_elf64_nhdr *nhdr;
     452                 :            :         struct nfp_elf_user_note *unote;
     453                 :          0 :         uint64_t sh_size = rte_le_to_cpu_64(sec->sh_size);
     454         [ #  # ]:          0 :         uint64_t sh_offset = rte_le_to_cpu_64(sec->sh_offset);
     455                 :            : 
     456                 :            :         if (!nfp_elf_check_sh_size(sh_size)) {
     457                 :          0 :                 PMD_DRV_LOG(ERR, "Invalid ELF section header, index %zu.", idx);
     458                 :          0 :                 return -EINVAL;
     459                 :            :         }
     460                 :            : 
     461                 :          0 :         shdrs_data = buf8 + sh_offset;
     462                 :          0 :         ectx->shdrs_data[idx] = shdrs_data;
     463                 :          0 :         ectx->shdrs_host_endian[idx] = 0;
     464                 :            : 
     465                 :            :         /* Extract notes that we recognise */
     466                 :            :         nhdr = (struct nfp_elf_elf64_nhdr *)shdrs_data;
     467                 :            : 
     468         [ #  # ]:          0 :         while ((uint8_t *)nhdr < (shdrs_data + sh_size)) {
     469                 :          0 :                 nnamesz  = rte_le_to_cpu_32(nhdr->n_namesz);
     470                 :          0 :                 ndescsz  = rte_le_to_cpu_32(nhdr->n_descsz);
     471                 :          0 :                 ntype    = rte_le_to_cpu_32(nhdr->n_type);
     472                 :          0 :                 nname    = (const char *)((uint8_t *)nhdr + sizeof(*nhdr));
     473                 :          0 :                 descword = (rte_le32_t *)((uint8_t *)nhdr + sizeof(*nhdr) +
     474                 :          0 :                                 ((nnamesz + UINT32_C(3)) & ~UINT32_C(3)));
     475                 :            : 
     476                 :          0 :                 err = nfp_elf_parse_note_name_nfp(ectx, idx, ndescsz, ntype, nname, descword);
     477         [ #  # ]:          0 :                 if (err != 0)
     478                 :          0 :                         return err;
     479                 :            : 
     480                 :          0 :                 nhdr = (struct nfp_elf_elf64_nhdr *)((uint8_t *)descword +
     481                 :          0 :                                 ((ndescsz + UINT32_C(3)) & ~UINT32_C(3)));
     482                 :            :         }
     483                 :            : 
     484         [ #  # ]:          0 :         if (ectx->user_note_cnt == 0)
     485                 :            :                 return 0;
     486                 :            : 
     487                 :          0 :         ectx->user_notes = calloc(ectx->user_note_cnt, sizeof(*ectx->user_notes));
     488         [ #  # ]:          0 :         if (ectx->user_notes == NULL) {
     489                 :          0 :                 PMD_DRV_LOG(ERR, "Out of memory.");
     490                 :          0 :                 return -ENOMEM;
     491                 :            :         }
     492                 :            : 
     493                 :            :         nhdr = (struct nfp_elf_elf64_nhdr *)shdrs_data;
     494                 :            :         unote = ectx->user_notes;
     495         [ #  # ]:          0 :         while ((uint8_t *)nhdr < (shdrs_data + sh_size)) {
     496                 :          0 :                 nnamesz = rte_le_to_cpu_32(nhdr->n_namesz);
     497                 :          0 :                 ndescsz = rte_le_to_cpu_32(nhdr->n_descsz);
     498                 :          0 :                 ntype   = rte_le_to_cpu_32(nhdr->n_type);
     499                 :          0 :                 nname   = (const char *)((uint8_t *)nhdr + sizeof(*nhdr));
     500                 :          0 :                 desc    = (uint8_t *)nhdr + sizeof(*nhdr) +
     501                 :          0 :                                 ((nnamesz + UINT32_C(3)) & ~UINT32_C(3));
     502                 :            : 
     503         [ #  # ]:          0 :                 if (strncmp(nname, NFP_ELT_NOTE_NAME_NFP_USER,
     504                 :            :                                 NFP_ELT_NOTE_NAME_NFP_USER_SZ) != 0)
     505                 :          0 :                         continue;
     506                 :            : 
     507         [ #  # ]:          0 :                 if (ntype != NFP_ELF_NT_NFP_USER)
     508                 :          0 :                         continue;
     509                 :            : 
     510                 :          0 :                 unote->name = (const char *)desc;
     511                 :          0 :                 nsz = strlen(unote->name) + 1;
     512         [ #  # ]:          0 :                 if (nsz % 4 != 0)
     513                 :          0 :                         nsz = ((nsz / 4) + 1) * 4;
     514         [ #  # ]:          0 :                 if (nsz > ndescsz) {
     515                 :          0 :                         PMD_DRV_LOG(ERR, "Invalid ELF USER NOTE descsz in section %zu.", idx);
     516                 :          0 :                         return -EINVAL;
     517                 :            :                 }
     518                 :            : 
     519                 :          0 :                 unote->data_sz = ndescsz - (uint32_t)nsz;
     520         [ #  # ]:          0 :                 if (unote->data_sz != 0)
     521                 :          0 :                         unote->data = desc + nsz;
     522                 :          0 :                 unote++;
     523                 :            : 
     524                 :          0 :                 nhdr = (struct nfp_elf_elf64_nhdr *)
     525                 :          0 :                                 (desc + ((ndescsz + UINT32_C(3)) & ~UINT32_C(3)));
     526                 :            :         }
     527                 :            : 
     528                 :            :         return 0;
     529                 :            : }
     530                 :            : 
     531                 :            : static int
     532                 :          0 : nfp_elf_parse_sht_meconfig(struct nfp_elf_elf64_shdr *sec,
     533                 :            :                 struct nfp_elf *ectx,
     534                 :            :                 size_t idx,
     535                 :            :                 uint8_t *buf8)
     536                 :            : {
     537                 :            :         size_t ent_cnt;
     538                 :            :         uint8_t *shdrs_data;
     539                 :          0 :         uint64_t sh_size = rte_le_to_cpu_64(sec->sh_size);
     540         [ #  # ]:          0 :         uint64_t sh_offset = rte_le_to_cpu_64(sec->sh_offset);
     541                 :            : 
     542                 :            :         if (!nfp_elf_check_sh_size(sh_size)) {
     543                 :          0 :                 PMD_DRV_LOG(ERR, "Invalid ELF section header, index %zu.", idx);
     544                 :          0 :                 return -EINVAL;
     545                 :            :         }
     546                 :            : 
     547         [ #  # ]:          0 :         shdrs_data = buf8 + sh_offset;
     548                 :            :         ent_cnt = nfp_elf_get_sec_ent_cnt(ectx, idx);
     549                 :          0 :         ectx->shdrs_data[idx] = shdrs_data;
     550                 :          0 :         ectx->meconfs = (struct nfp_elf_elf_meconfig *)shdrs_data;
     551                 :          0 :         ectx->meconfs_cnt = ent_cnt;
     552                 :          0 :         ectx->shdrs_host_endian[idx] = 1;
     553                 :            : 
     554                 :          0 :         return 0;
     555                 :            : }
     556                 :            : 
     557                 :            : static int
     558                 :          0 : nfp_elf_parse_sht_initreg(struct nfp_elf_elf64_shdr *sec,
     559                 :            :                 struct nfp_elf *ectx,
     560                 :            :                 size_t idx,
     561                 :            :                 uint8_t *buf8)
     562                 :            : {
     563                 :          0 :         uint64_t sh_size = rte_le_to_cpu_64(sec->sh_size);
     564                 :          0 :         uint64_t sh_offset = rte_le_to_cpu_64(sec->sh_offset);
     565         [ #  # ]:          0 :         uint64_t sh_entsize = rte_le_to_cpu_64(sec->sh_entsize);
     566                 :            : 
     567                 :            :         if (!nfp_elf_arch_is_thornham(ectx)) {
     568                 :          0 :                 PMD_DRV_LOG(ERR, "Section not supported for target arch.");
     569                 :          0 :                 return -ENOTSUP;
     570                 :            :         }
     571                 :            : 
     572         [ #  # ]:          0 :         if (sh_entsize != sizeof(struct nfp_elf_elf_initregentry) ||
     573                 :            :                         !nfp_elf_check_sh_size(sh_size)) {
     574                 :          0 :                 PMD_DRV_LOG(ERR, "Invalid ELF section header, index %zu.", idx);
     575                 :          0 :                 return -EINVAL;
     576                 :            :         }
     577                 :            : 
     578                 :          0 :         ectx->shdrs_data[idx] = buf8 + sh_offset;
     579                 :          0 :         ectx->shdrs_host_endian[idx] = 1;
     580                 :            : 
     581                 :          0 :         return 0;
     582                 :            : }
     583                 :            : 
     584                 :            : static int
     585                 :          0 : nfp_elf_parse_sht_symtab(struct nfp_elf_elf64_shdr *sec,
     586                 :            :                 struct nfp_elf *ectx,
     587                 :            :                 size_t idx,
     588                 :            :                 uint8_t *buf8)
     589                 :            : {
     590                 :          0 :         uint64_t sh_size = rte_le_to_cpu_64(sec->sh_size);
     591                 :          0 :         uint64_t sh_offset = rte_le_to_cpu_64(sec->sh_offset);
     592                 :          0 :         uint64_t sh_entsize = rte_le_to_cpu_64(sec->sh_entsize);
     593                 :            : 
     594         [ #  # ]:          0 :         if (sh_entsize != sizeof(struct nfp_elf_elf64_sym) ||
     595                 :            :                         !nfp_elf_check_sh_size(sh_size)) {
     596                 :          0 :                 PMD_DRV_LOG(ERR, "Invalid ELF section header, index %zu.", idx);
     597                 :          0 :                 return -EINVAL;
     598                 :            :         }
     599                 :            : 
     600                 :          0 :         ectx->shdrs_data[idx] = buf8 + sh_offset;
     601                 :          0 :         ectx->shdrs_host_endian[ectx->shdr_idx_symtab] = 1;
     602                 :            : 
     603                 :          0 :         return 0;
     604                 :            : }
     605                 :            : 
     606                 :            : static int
     607                 :          0 : nfp_elf_populate_fw_mip(struct nfp_elf *ectx,
     608                 :            :                 uint8_t *buf8)
     609                 :            : {
     610                 :            :         uint8_t *pu8;
     611                 :            :         const char *nx;
     612                 :            :         ssize_t tab_sz;
     613                 :            :         uint64_t sh_size;
     614                 :            :         const char *str_tab;
     615                 :            :         uint64_t sh_offset;
     616                 :            :         uint32_t first_entry;
     617                 :            :         const struct nfp_mip *mip;
     618                 :            :         struct nfp_elf_elf64_shdr *sec;
     619                 :            :         const struct nfp_mip_entry *ent;
     620                 :            :         const struct nfp_mip_fwinfo_entry *fwinfo;
     621                 :            : 
     622                 :          0 :         sec = &ectx->shdrs[ectx->mip_shndx];
     623                 :          0 :         sh_size = rte_le_to_cpu_64(sec->sh_size);
     624                 :          0 :         sh_offset = rte_le_to_cpu_64(sec->sh_offset);
     625                 :          0 :         pu8 = buf8 + sh_offset + ectx->mip_sh_off;
     626                 :            :         mip = (const struct nfp_mip *)pu8;
     627                 :          0 :         first_entry = rte_le_to_cpu_32(mip->first_entry);
     628                 :            : 
     629         [ #  # ]:          0 :         if (mip->signature != NFP_MIP_SIGNATURE) {
     630                 :          0 :                 PMD_DRV_LOG(ERR, "Incorrect MIP signature %#08x",
     631                 :            :                                 rte_le_to_cpu_32(mip->signature));
     632                 :          0 :                 return -EINVAL;
     633                 :            :         }
     634                 :            : 
     635                 :          0 :         ectx->fw_mip.shndx = ectx->mip_shndx;
     636                 :          0 :         ectx->fw_mip.sh_offset = ectx->mip_sh_off;
     637                 :          0 :         ectx->fw_mip.mip_ver = mip->mip_version;
     638                 :            : 
     639         [ #  # ]:          0 :         if (ectx->fw_mip.mip_ver != NFP_MIP_VERSION) {
     640                 :          0 :                 PMD_DRV_LOG(ERR, "MIP note pointer does not point to recognised version.");
     641                 :          0 :                 return -EINVAL;
     642                 :            :         }
     643                 :            : 
     644                 :          0 :         ectx->fw_mip.fw_version   = mip->version;
     645                 :          0 :         ectx->fw_mip.fw_buildnum  = mip->buildnum;
     646                 :          0 :         ectx->fw_mip.fw_buildtime = mip->buildtime;
     647         [ #  # ]:          0 :         strncpy(ectx->fw_mip.fw_name, mip->name, 16);
     648                 :            : 
     649                 :            :         /*
     650                 :            :          * If there is a FWINFO v1 entry, it will be first and
     651                 :            :          * right after the MIP itself, so in the same section.
     652                 :            :          */
     653         [ #  # ]:          0 :         if (ectx->mip_sh_off + first_entry + sizeof(*ent) < sh_size) {
     654                 :          0 :                 pu8 += first_entry;
     655                 :            :                 ent = (const struct nfp_mip_entry *)pu8;
     656   [ #  #  #  # ]:          0 :                 if (ent->type == NFP_MIP_TYPE_FWINFO && ent->version == 1) {
     657                 :            :                         pu8 += sizeof(*ent);
     658                 :            :                         fwinfo = (const struct nfp_mip_fwinfo_entry *)pu8;
     659         [ #  # ]:          0 :                         if (fwinfo->kv_len != 0) {
     660                 :          0 :                                 ectx->fw_info_strtab_sz = fwinfo->kv_len;
     661                 :          0 :                                 ectx->fw_info_strtab = fwinfo->key_value_strs;
     662                 :            :                         }
     663                 :            :                 }
     664                 :            :         }
     665                 :            : 
     666                 :          0 :         str_tab = ectx->fw_info_strtab;
     667                 :          0 :         tab_sz = (ssize_t)ectx->fw_info_strtab_sz;
     668                 :          0 :         ectx->fw_mip.fw_typeid = nfp_elf_fwinfo_lookup(str_tab, tab_sz, "TypeId");
     669                 :            : 
     670                 :            :         /*
     671                 :            :          * TypeId will be the last reserved key-value pair, so skip
     672                 :            :          * to the first entry after it for the user values.
     673                 :            :          */
     674         [ #  # ]:          0 :         if (ectx->fw_mip.fw_typeid == NULL)
     675                 :            :                 return 0;
     676                 :            : 
     677                 :          0 :         nx = nfp_elf_fwinfo_next(ectx, ectx->fw_mip.fw_typeid);
     678         [ #  # ]:          0 :         if (nx == NULL)
     679                 :          0 :                 ectx->fw_info_strtab_sz = 0;
     680                 :            :         else
     681                 :          0 :                 ectx->fw_info_strtab_sz -= (nx - ectx->fw_info_strtab);
     682                 :          0 :         ectx->fw_info_strtab = nx;
     683                 :            : 
     684                 :          0 :         return 0;
     685                 :            : }
     686                 :            : 
     687                 :            : static int
     688                 :          0 : nfp_elf_read_file_headers(struct nfp_elf *ectx,
     689                 :            :                 void *buf)
     690                 :            : {
     691                 :            :         uint16_t e_type;
     692                 :            :         uint32_t e_flags;
     693                 :            :         uint32_t e_version;
     694                 :            :         uint16_t e_machine;
     695                 :            : 
     696                 :          0 :         ectx->ehdr = buf;
     697                 :          0 :         e_type = rte_le_to_cpu_16(ectx->ehdr->e_type);
     698                 :          0 :         e_flags = rte_le_to_cpu_32(ectx->ehdr->e_flags);
     699                 :          0 :         e_version = rte_le_to_cpu_32(ectx->ehdr->e_version);
     700                 :          0 :         e_machine = rte_le_to_cpu_16(ectx->ehdr->e_machine);
     701                 :            : 
     702      [ #  #  # ]:          0 :         switch (e_machine) {
     703                 :          0 :         case NFP_ELF_EM_NFP:
     704                 :          0 :                 ectx->family = (e_flags >> NFP_ELF_EF_NFP_FAMILY_LSB)
     705                 :          0 :                                 & NFP_ELF_EF_NFP_FAMILY_MASK;
     706                 :          0 :                 break;
     707                 :          0 :         case NFP_ELF_EM_NFP6000:
     708                 :          0 :                 ectx->family = NFP_CHIP_FAMILY_NFP6000;
     709                 :          0 :                 break;
     710                 :          0 :         default:
     711                 :          0 :                 PMD_DRV_LOG(ERR, "Invalid ELF machine type.");
     712                 :          0 :                 return -EINVAL;
     713                 :            :         }
     714                 :            : 
     715                 :          0 :         if ((e_type != NFP_ELF_ET_EXEC && e_type != NFP_ELF_ET_REL &&
     716   [ #  #  #  # ]:          0 :                         e_type != NFP_ELF_ET_NFP_PARTIAL_EXEC &&
     717         [ #  # ]:          0 :                         e_type != NFP_ELF_ET_NFP_PARTIAL_REL) ||
     718                 :          0 :                         e_version != NFP_ELF_EV_CURRENT ||
     719         [ #  # ]:          0 :                         ectx->ehdr->e_ehsize != sizeof(struct nfp_elf_elf64_ehdr) ||
     720         [ #  # ]:          0 :                         ectx->ehdr->e_shentsize != sizeof(struct nfp_elf_elf64_shdr)) {
     721                 :          0 :                 PMD_DRV_LOG(ERR, "Invalid ELF file header.");
     722                 :          0 :                 return -EINVAL;
     723                 :            :         }
     724                 :            : 
     725         [ #  # ]:          0 :         if (ectx->ehdr->e_shoff < ectx->ehdr->e_ehsize) {
     726                 :          0 :                 PMD_DRV_LOG(ERR, "Invalid ELF header content.");
     727                 :          0 :                 return -EINVAL;
     728                 :            :         }
     729                 :            : 
     730         [ #  # ]:          0 :         if (ectx->ehdr->e_shstrndx >= ectx->ehdr->e_shnum) {
     731                 :          0 :                 PMD_DRV_LOG(ERR, "Invalid ELF header content.");
     732                 :          0 :                 return -EINVAL;
     733                 :            :         }
     734                 :            : 
     735                 :            :         return 0;
     736                 :            : }
     737                 :            : 
     738                 :            : static int
     739                 :          0 : nfp_elf_read_section_headers(struct nfp_elf *ectx,
     740                 :            :                 uint8_t *buf8,
     741                 :            :                 size_t buf_len)
     742                 :            : {
     743                 :            :         size_t idx;
     744                 :            :         int err = 0;
     745                 :            :         uint8_t *pu8;
     746                 :            :         uint64_t sh_size;
     747                 :            :         uint64_t sh_offset;
     748                 :            :         uint64_t sh_entsize;
     749                 :            :         struct nfp_elf_elf64_shdr *sec;
     750                 :          0 :         uint64_t e_shoff = rte_le_to_cpu_16(ectx->ehdr->e_shoff);
     751                 :          0 :         uint16_t e_shnum = rte_le_to_cpu_16(ectx->ehdr->e_shnum);
     752                 :            : 
     753         [ #  # ]:          0 :         if (buf_len < e_shoff + ((size_t)e_shnum * sizeof(*sec))) {
     754                 :          0 :                 PMD_DRV_LOG(ERR, "ELF data too short.");
     755                 :          0 :                 return -EINVAL;
     756                 :            :         }
     757                 :            : 
     758                 :          0 :         pu8 = buf8 + e_shoff;
     759                 :            : 
     760         [ #  # ]:          0 :         if (e_shnum == 0) {
     761                 :          0 :                 ectx->shdrs = NULL;
     762                 :          0 :                 ectx->shdrs_data = NULL;
     763                 :          0 :                 ectx->shdrs_host_endian = NULL;
     764                 :          0 :                 ectx->shdrs_cnt = 0;
     765                 :          0 :                 return 0;
     766                 :            :         }
     767                 :            : 
     768                 :          0 :         ectx->shdrs = calloc(e_shnum, sizeof(*ectx->shdrs));
     769         [ #  # ]:          0 :         if (ectx->shdrs == NULL) {
     770                 :          0 :                 PMD_DRV_LOG(ERR, "Out of memory.");
     771                 :          0 :                 return -ENOMEM;
     772                 :            :         }
     773                 :            : 
     774                 :          0 :         ectx->shdrs_data = calloc(e_shnum, sizeof(void *));
     775         [ #  # ]:          0 :         if (ectx->shdrs_data == NULL) {
     776                 :          0 :                 PMD_DRV_LOG(ERR, "Out of memory.");
     777                 :            :                 err = -ENOMEM;
     778                 :          0 :                 goto free_shdrs;
     779                 :            :         }
     780                 :            : 
     781                 :          0 :         ectx->shdrs_host_endian = calloc(e_shnum, sizeof(ectx->shdrs_host_endian[0]));
     782         [ #  # ]:          0 :         if (ectx->shdrs_host_endian == NULL) {
     783                 :          0 :                 PMD_DRV_LOG(ERR, "Out of memory.");
     784                 :            :                 err = -ENOMEM;
     785                 :          0 :                 goto free_shdrs_data;
     786                 :            :         }
     787                 :            : 
     788                 :            :         memcpy(ectx->shdrs, pu8, e_shnum * sizeof(*ectx->shdrs));
     789                 :          0 :         ectx->shdrs_cnt = e_shnum;
     790                 :            : 
     791         [ #  # ]:          0 :         for (idx = 0, sec = ectx->shdrs; idx < ectx->shdrs_cnt; idx++, sec++) {
     792                 :          0 :                 sh_size = rte_le_to_cpu_64(sec->sh_size);
     793                 :          0 :                 sh_offset = rte_le_to_cpu_64(sec->sh_offset);
     794                 :          0 :                 sh_entsize = rte_le_to_cpu_64(sec->sh_entsize);
     795                 :            : 
     796   [ #  #  #  # ]:          0 :                 if (sh_entsize != 0 && (sh_size % sh_entsize != 0)) {
     797                 :          0 :                         PMD_DRV_LOG(ERR, "Invalid ELF section header, index %zu.", idx);
     798                 :            :                         err = -EINVAL;
     799                 :          0 :                         goto free_shdrs_host_endian;
     800                 :            :                 }
     801                 :            : 
     802   [ #  #  #  #  :          0 :                 switch (rte_le_to_cpu_32(sec->sh_type)) {
                #  #  # ]
     803                 :          0 :                 case NFP_ELF_SHT_REL:
     804                 :          0 :                         err = nfp_elf_parse_sht_rel(sec, ectx, idx, buf8);
     805         [ #  # ]:          0 :                         if (err != 0) {
     806                 :          0 :                                 PMD_DRV_LOG(ERR, "Failed to parse sht rel.");
     807                 :          0 :                                 goto free_shdrs_host_endian;
     808                 :            :                         }
     809                 :            :                         break;
     810                 :          0 :                 case NFP_ELF_SHT_NOTE:
     811                 :          0 :                         err = nfp_elf_parse_sht_note(sec, ectx, idx, buf8);
     812         [ #  # ]:          0 :                         if (err != 0) {
     813                 :          0 :                                 PMD_DRV_LOG(ERR, "Failed to parse sht note.");
     814                 :          0 :                                 goto free_shdrs_host_endian;
     815                 :            :                         }
     816                 :            :                         break;
     817                 :          0 :                 case NFP_ELF_SHT_NFP_MECONFIG:
     818                 :          0 :                         err = nfp_elf_parse_sht_meconfig(sec, ectx, idx, buf8);
     819         [ #  # ]:          0 :                         if (err != 0) {
     820                 :          0 :                                 PMD_DRV_LOG(ERR, "Failed to parse sht meconfig.");
     821                 :          0 :                                 goto free_shdrs_host_endian;
     822                 :            :                         }
     823                 :            :                         break;
     824                 :          0 :                 case NFP_ELF_SHT_NFP_INITREG:
     825                 :          0 :                         err = nfp_elf_parse_sht_initreg(sec, ectx, idx, buf8);
     826         [ #  # ]:          0 :                         if (err != 0) {
     827                 :          0 :                                 PMD_DRV_LOG(ERR, "Failed to parse sht initregp.");
     828                 :          0 :                                 goto free_shdrs_host_endian;
     829                 :            :                         }
     830                 :            :                         break;
     831                 :          0 :                 case NFP_ELF_SHT_SYMTAB:
     832                 :          0 :                         err = nfp_elf_parse_sht_symtab(sec, ectx, idx, buf8);
     833         [ #  # ]:          0 :                         if (err != 0) {
     834                 :          0 :                                 PMD_DRV_LOG(ERR, "Failed to parse sht symtab.");
     835                 :          0 :                                 goto free_shdrs_host_endian;
     836                 :            :                         }
     837                 :            :                         break;
     838                 :            :                 case NFP_ELF_SHT_NOBITS:
     839                 :            :                 case NFP_ELF_SHT_NULL:
     840                 :            :                         break;
     841                 :          0 :                 default:
     842         [ #  # ]:          0 :                         if (sh_offset > 0 && sh_size <= 0)
     843                 :            :                                 break;
     844                 :            : 
     845                 :            :                         /*
     846                 :            :                          * Limit sections to 4GiB, because they won't need to be this large
     847                 :            :                          * and this ensures we can handle the file on 32-bit hosts without
     848                 :            :                          * unexpected problems.
     849                 :            :                          */
     850         [ #  # ]:          0 :                         if (sh_size > UINT32_MAX) {
     851                 :          0 :                                 PMD_DRV_LOG(ERR, "Invalid ELF section header, index %zu.", idx);
     852                 :            :                                 err = -EINVAL;
     853                 :          0 :                                 goto free_shdrs_host_endian;
     854                 :            :                         }
     855                 :            : 
     856                 :          0 :                         pu8 = buf8 + sh_offset;
     857                 :          0 :                         ectx->shdrs_data[idx] = pu8;
     858                 :          0 :                         ectx->shdrs_host_endian[idx] = 0;
     859                 :          0 :                         break;
     860                 :            :                 }
     861                 :            :         }
     862                 :            : 
     863                 :            :         return 0;
     864                 :            : 
     865                 :          0 : free_shdrs_host_endian:
     866                 :          0 :         free(ectx->shdrs_host_endian);
     867                 :          0 : free_shdrs_data:
     868                 :          0 :         free(ectx->shdrs_data);
     869                 :          0 : free_shdrs:
     870                 :          0 :         free(ectx->shdrs);
     871                 :            : 
     872                 :          0 :         return err;
     873                 :            : }
     874                 :            : 
     875                 :            : static int
     876                 :          0 : nfp_elf_read_shstrtab(struct nfp_elf *ectx)
     877                 :            : {
     878                 :            :         struct nfp_elf_elf64_shdr *sec;
     879                 :          0 :         uint16_t e_shstrndx = rte_le_to_cpu_16(ectx->ehdr->e_shstrndx);
     880                 :            : 
     881         [ #  # ]:          0 :         if (ectx->ehdr->e_shnum <= ectx->ehdr->e_shstrndx) {
     882                 :          0 :                 PMD_DRV_LOG(ERR, "Invalid Index.");
     883                 :          0 :                 return -EINVAL;
     884                 :            :         }
     885                 :            : 
     886                 :          0 :         sec = &ectx->shdrs[e_shstrndx];
     887   [ #  #  #  # ]:          0 :         if (sec == NULL || rte_le_to_cpu_32(sec->sh_type) != NFP_ELF_SHT_STRTAB) {
     888                 :          0 :                 PMD_DRV_LOG(ERR, "Invalid ELF shstrtab.");
     889                 :          0 :                 return -EINVAL;
     890                 :            :         }
     891                 :            : 
     892                 :          0 :         ectx->shstrtab = ectx->shdrs_data[e_shstrndx];
     893                 :          0 :         ectx->shstrtab_sz = rte_le_to_cpu_64(sec->sh_size);
     894                 :            : 
     895                 :          0 :         return 0;
     896                 :            : }
     897                 :            : 
     898                 :            : static int
     899                 :          0 : nfp_elf_read_first_symtab(struct nfp_elf *ectx)
     900                 :            : {
     901                 :            :         size_t idx;
     902                 :            :         uint32_t sh_type;
     903                 :            :         uint64_t sh_size;
     904                 :            :         struct nfp_elf_elf64_shdr *sec = NULL;
     905                 :            : 
     906         [ #  # ]:          0 :         for (idx = 0; idx < ectx->shdrs_cnt; idx++) {
     907                 :          0 :                 sec = &ectx->shdrs[idx];
     908         [ #  # ]:          0 :                 if (sec != NULL) {
     909                 :          0 :                         sh_type = rte_le_to_cpu_32(sec->sh_type);
     910         [ #  # ]:          0 :                         if (sh_type == NFP_ELF_SHT_SYMTAB)
     911                 :            :                                 break;
     912                 :            :                 }
     913                 :            :         }
     914                 :            : 
     915         [ #  # ]:          0 :         if (sec == NULL)
     916                 :            :                 return -EINVAL;
     917                 :            : 
     918                 :          0 :         sh_size = rte_le_to_cpu_64(sec->sh_size);
     919                 :            : 
     920   [ #  #  #  # ]:          0 :         if (idx < ectx->shdrs_cnt && sh_type == NFP_ELF_SHT_SYMTAB) {
     921                 :          0 :                 ectx->shdr_idx_symtab = idx;
     922         [ #  # ]:          0 :                 ectx->syms = ectx->shdrs_data[idx];
     923                 :          0 :                 ectx->syms_cnt = nfp_elf_get_sec_ent_cnt(ectx, idx);
     924                 :            : 
     925                 :            :                 /* Load symtab's strtab */
     926                 :          0 :                 idx = rte_le_to_cpu_32(sec->sh_link);
     927                 :            : 
     928   [ #  #  #  # ]:          0 :                 if (idx == NFP_ELF_SHN_UNDEF || idx >= ectx->shdrs_cnt) {
     929                 :          0 :                         PMD_DRV_LOG(ERR, "ELF symtab has no strtab.");
     930                 :          0 :                         return -EINVAL;
     931                 :            :                 }
     932                 :            : 
     933                 :          0 :                 sec = &ectx->shdrs[idx];
     934                 :          0 :                 sh_type = rte_le_to_cpu_32(sec->sh_type);
     935         [ #  # ]:          0 :                 if (sh_type != NFP_ELF_SHT_STRTAB) {
     936                 :          0 :                         PMD_DRV_LOG(ERR, "ELF symtab has no strtab.");
     937                 :          0 :                         return -EINVAL;
     938                 :            :                 }
     939                 :            : 
     940                 :            :                 if (!nfp_elf_check_sh_size(sh_size)) {
     941                 :          0 :                         PMD_DRV_LOG(ERR, "ELF symtab has invalid strtab.");
     942                 :          0 :                         return -EINVAL;
     943                 :            :                 }
     944                 :            : 
     945                 :          0 :                 ectx->symstrtab = ectx->shdrs_data[idx];
     946                 :          0 :                 ectx->symstrtab_sz = sh_size;
     947                 :            :         }
     948                 :            : 
     949                 :            :         return 0;
     950                 :            : }
     951                 :            : 
     952                 :            : static int
     953                 :            : nfp_elf_is_valid_file(uint8_t *buf8)
     954                 :            : {
     955                 :          0 :         if (buf8[NFP_ELF_EI_MAG0] != NFP_ELF_ELFMAG0 ||
     956         [ #  # ]:          0 :                         buf8[NFP_ELF_EI_MAG1] != NFP_ELF_ELFMAG1 ||
     957         [ #  # ]:          0 :                         buf8[NFP_ELF_EI_MAG2] != NFP_ELF_ELFMAG2 ||
     958         [ #  # ]:          0 :                         buf8[NFP_ELF_EI_MAG3] != NFP_ELF_ELFMAG3 ||
     959         [ #  # ]:          0 :                         buf8[NFP_ELF_EI_VERSION] != NFP_ELF_EV_CURRENT ||
     960         [ #  # ]:          0 :                         buf8[NFP_ELF_EI_DATA] != NFP_ELF_ELFDATA2LSB)
     961                 :            :                 return -EINVAL;
     962                 :            : 
     963                 :            :         return 0;
     964                 :            : }
     965                 :            : 
     966                 :            : static int
     967                 :            : nfp_elf_is_valid_class(uint8_t *buf8)
     968                 :            : {
     969         [ #  # ]:          0 :         if (buf8[NFP_ELF_EI_CLASS] != NFP_ELF_ELFCLASS64)
     970                 :            :                 return -EINVAL;
     971                 :            : 
     972                 :            :         return 0;
     973                 :            : }
     974                 :            : 
     975                 :            : static struct nfp_elf *
     976                 :          0 : nfp_elf_mutable_buf(void *buf,
     977                 :            :                 size_t buf_len)
     978                 :            : {
     979                 :            :         int err = 0;
     980                 :            :         uint8_t *buf8 = buf;
     981                 :            :         struct nfp_elf *ectx;
     982                 :            : 
     983         [ #  # ]:          0 :         if (buf == NULL) {
     984                 :          0 :                 PMD_DRV_LOG(ERR, "Invalid parameters.");
     985                 :          0 :                 return NULL;
     986                 :            :         }
     987                 :            : 
     988         [ #  # ]:          0 :         if (buf_len < sizeof(struct nfp_elf_elf64_ehdr)) {
     989                 :          0 :                 PMD_DRV_LOG(ERR, "ELF data too short.");
     990                 :          0 :                 return NULL;
     991                 :            :         }
     992                 :            : 
     993                 :          0 :         ectx = calloc(1, sizeof(struct nfp_elf));
     994         [ #  # ]:          0 :         if (ectx == NULL) {
     995                 :          0 :                 PMD_DRV_LOG(ERR, "Out of memory.");
     996                 :          0 :                 return NULL;
     997                 :            :         }
     998                 :            : 
     999                 :          0 :         ectx->rev_min = -1;
    1000                 :          0 :         ectx->rev_max = -1;
    1001         [ #  # ]:          0 :         ectx->mip_sh_off = UINT64_MAX;
    1002                 :            : 
    1003                 :            :         err = nfp_elf_is_valid_file(buf8);
    1004                 :            :         if (err != 0) {
    1005                 :          0 :                 PMD_DRV_LOG(ERR, "Not a valid ELF file.");
    1006                 :          0 :                 goto elf_free;
    1007                 :            :         }
    1008                 :            : 
    1009                 :            :         err = nfp_elf_is_valid_class(buf8);
    1010                 :            :         if (err != 0) {
    1011                 :          0 :                 PMD_DRV_LOG(ERR, "Unknown ELF class.");
    1012                 :          0 :                 goto elf_free;
    1013                 :            :         }
    1014                 :            : 
    1015                 :          0 :         err = nfp_elf_read_file_headers(ectx, buf);
    1016         [ #  # ]:          0 :         if (err != 0) {
    1017                 :          0 :                 PMD_DRV_LOG(ERR, "Failed to read file headers.");
    1018                 :          0 :                 goto elf_free;
    1019                 :            :         }
    1020                 :            : 
    1021                 :          0 :         err = nfp_elf_read_section_headers(ectx, buf8, buf_len);
    1022         [ #  # ]:          0 :         if (err != 0) {
    1023                 :          0 :                 PMD_DRV_LOG(ERR, "Failed to read section headers.");
    1024                 :          0 :                 goto elf_free;
    1025                 :            :         }
    1026                 :            : 
    1027                 :          0 :         err = nfp_elf_read_shstrtab(ectx);
    1028         [ #  # ]:          0 :         if (err != 0) {
    1029                 :          0 :                 PMD_DRV_LOG(ERR, "Failed to read shstrtab.");
    1030                 :          0 :                 goto elf_free;
    1031                 :            :         }
    1032                 :            : 
    1033                 :            :         /* Read first symtab if any, assuming it's the primary or only one */
    1034                 :          0 :         err = nfp_elf_read_first_symtab(ectx);
    1035         [ #  # ]:          0 :         if (err != 0) {
    1036                 :          0 :                 PMD_DRV_LOG(ERR, "Failed to read first symtab.");
    1037                 :          0 :                 goto elf_free;
    1038                 :            :         }
    1039                 :            : 
    1040                 :            :         /* Populate the fw_mip struct if we have a .note for it */
    1041         [ #  # ]:          0 :         if (ectx->mip_shndx != 0) {
    1042                 :          0 :                 err = nfp_elf_populate_fw_mip(ectx, buf8);
    1043         [ #  # ]:          0 :                 if (err != 0) {
    1044                 :          0 :                         PMD_DRV_LOG(ERR, "Failed to populate the fw mip.");
    1045                 :          0 :                         goto elf_free;
    1046                 :            :                 }
    1047                 :            :         }
    1048                 :            : 
    1049                 :          0 :         ectx->_buf = buf;
    1050                 :          0 :         ectx->_bufsz = 0;
    1051                 :            : 
    1052                 :          0 :         return ectx;
    1053                 :            : 
    1054                 :          0 : elf_free:
    1055                 :          0 :         nfp_elf_free(ectx);
    1056                 :            : 
    1057                 :          0 :         return NULL;
    1058                 :            : }
    1059                 :            : 
    1060                 :            : int
    1061                 :          0 : nfp_elf_get_fw_version(uint32_t *fw_version,
    1062                 :            :                 char *fw_name)
    1063                 :            : {
    1064                 :            :         void *fw_buf;
    1065                 :            :         size_t fsize;
    1066                 :            :         struct nfp_elf *elf;
    1067                 :            : 
    1068         [ #  # ]:          0 :         if (rte_firmware_read(fw_name, &fw_buf, &fsize) != 0) {
    1069                 :          0 :                 PMD_DRV_LOG(ERR, "firmware %s not found!", fw_name);
    1070                 :          0 :                 return -ENOENT;
    1071                 :            :         }
    1072                 :            : 
    1073                 :          0 :         elf = nfp_elf_mutable_buf(fw_buf, fsize);
    1074         [ #  # ]:          0 :         if (elf == NULL) {
    1075                 :          0 :                 PMD_DRV_LOG(ERR, "Parse nffw file failed.");
    1076                 :          0 :                 free(fw_buf);
    1077                 :          0 :                 return -EIO;
    1078                 :            :         }
    1079                 :            : 
    1080                 :          0 :         *fw_version = rte_le_to_cpu_32(elf->fw_mip.fw_version);
    1081                 :            : 
    1082                 :          0 :         nfp_elf_free(elf);
    1083                 :          0 :         free(fw_buf);
    1084                 :          0 :         return 0;
    1085                 :            : }
    1086                 :            : 

Generated by: LCOV version 1.14