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