xref: /dpdk/drivers/net/nfp/nfpcore/nfp_elf.c (revision b6de43530dfa30cbf6b70857e3835099701063d4)
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