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