xref: /dpdk/drivers/net/nfp/nfpcore/nfp_elf.c (revision e9fd1ebf981f361844aea9ec94e17f4bda5e1479)
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(struct nfp_elf *ectx,
328 		const char *key)
329 {
330 	size_t s_len;
331 	const char *s;
332 	size_t key_len = strlen(key);
333 	const char *strtab = ectx->fw_info_strtab;
334 	ssize_t tab_sz = (ssize_t)ectx->fw_info_strtab_sz;
335 
336 	if (strtab == NULL)
337 		return NULL;
338 
339 	for (s = strtab, s_len = strlen(s) + 1;
340 			(s[0] != '\0') && (tab_sz > 0);
341 			s_len = strlen(s) + 1, tab_sz -= s_len, s += s_len) {
342 		if ((strncmp(s, key, key_len) == 0) && (s[key_len] == '='))
343 			return &s[key_len + 1];
344 	}
345 
346 	return NULL;
347 }
348 
349 static bool
350 nfp_elf_arch_is_thornham(struct nfp_elf *ectx)
351 {
352 	if (ectx == NULL)
353 		return false;
354 
355 	if (ectx->family == NFP_CHIP_FAMILY_NFP6000 || ectx->family == NFP_CHIP_FAMILY_NFP3800)
356 		return true;
357 
358 	return false;
359 }
360 
361 static int
362 nfp_elf_parse_sht_rel(struct nfp_elf_elf64_shdr *sec,
363 		struct nfp_elf *ectx,
364 		size_t idx,
365 		uint8_t *buf8)
366 {
367 	uint64_t sh_size = rte_le_to_cpu_64(sec->sh_size);
368 	uint64_t sh_offset = rte_le_to_cpu_64(sec->sh_offset);
369 	uint64_t sh_entsize = rte_le_to_cpu_64(sec->sh_entsize);
370 
371 	if (sh_entsize != sizeof(struct nfp_elf_elf64_rel)) {
372 		PMD_DRV_LOG(ERR, "Invalid ELF section header, index %zu.", idx);
373 		return -EINVAL;
374 	}
375 
376 	if (!nfp_elf_check_sh_size(sh_size)) {
377 		PMD_DRV_LOG(ERR, "Invalid ELF section header, index %zu.", idx);
378 		return -EINVAL;
379 	}
380 
381 	ectx->shdrs_data[idx] = buf8 + sh_offset;
382 	ectx->shdrs_host_endian[idx] = 1;
383 
384 	return 0;
385 }
386 
387 static int
388 nfp_elf_parse_note_name_nfp(struct nfp_elf *ectx,
389 		size_t idx,
390 		uint32_t ndescsz,
391 		uint32_t ntype,
392 		const char *nname,
393 		rte_le32_t *descword)
394 {
395 	if (strncmp(nname, NFP_ELT_NOTE_NAME_NFP, NFP_ELT_NOTE_NAME_NFP_SZ) == 0) {
396 		switch (ntype) {
397 		case NFP_ELF_NT_NFP_REVS:
398 			if (ndescsz != 8) {
399 				PMD_DRV_LOG(ERR, "Invalid ELF NOTE descsz in section %zu.", idx);
400 				return -EINVAL;
401 			}
402 
403 			ectx->rev_min = (int)rte_le_to_cpu_32(descword[0]);
404 			ectx->rev_max = (int)rte_le_to_cpu_32(descword[1]);
405 			break;
406 		case NFP_ELF_NT_NFP_MIP_LOCATION:
407 			if (ndescsz != 12) {
408 				PMD_DRV_LOG(ERR, "Invalid ELF NOTE descsz in section %zu.", idx);
409 				return -EINVAL;
410 			}
411 
412 			ectx->mip_shndx = rte_le_to_cpu_32(descword[0]);
413 			if (ectx->mip_shndx == 0) {
414 				ectx->mip_sh_off = 0;
415 				break;
416 			}
417 
418 			if (ectx->mip_shndx >= ectx->shdrs_cnt) {
419 				PMD_DRV_LOG(ERR, "Invalid ELF NOTE shndx in section %zu.", idx);
420 				return -EINVAL;
421 			}
422 
423 			ectx->mip_sh_off = rte_le_to_cpu_32(descword[1]) |
424 					(uint64_t)rte_le_to_cpu_32(descword[2]) << 32;
425 			break;
426 		default:
427 			break;
428 		}
429 	} else if (strncmp(nname, NFP_ELT_NOTE_NAME_NFP_USER,
430 			NFP_ELT_NOTE_NAME_NFP_USER_SZ) == 0 && ntype == NFP_ELF_NT_NFP_USER) {
431 		ectx->user_note_cnt++;
432 	}
433 
434 	return 0;
435 }
436 
437 static int
438 nfp_elf_parse_sht_note(struct nfp_elf_elf64_shdr *sec,
439 		struct nfp_elf *ectx,
440 		size_t idx,
441 		uint8_t *buf8)
442 {
443 	int err;
444 	size_t nsz;
445 	uint8_t *desc;
446 	uint32_t ntype;
447 	uint32_t nnamesz;
448 	uint32_t ndescsz;
449 	const char *nname;
450 	uint8_t *shdrs_data;
451 	rte_le32_t *descword;
452 	struct nfp_elf_elf64_nhdr *nhdr;
453 	struct nfp_elf_user_note *unote;
454 	uint64_t sh_size = rte_le_to_cpu_64(sec->sh_size);
455 	uint64_t sh_offset = rte_le_to_cpu_64(sec->sh_offset);
456 
457 	if (!nfp_elf_check_sh_size(sh_size)) {
458 		PMD_DRV_LOG(ERR, "Invalid ELF section header, index %zu.", idx);
459 		return -EINVAL;
460 	}
461 
462 	shdrs_data = buf8 + sh_offset;
463 	ectx->shdrs_data[idx] = shdrs_data;
464 	ectx->shdrs_host_endian[idx] = 0;
465 
466 	/* Extract notes that we recognise */
467 	nhdr = (struct nfp_elf_elf64_nhdr *)shdrs_data;
468 
469 	while ((uint8_t *)nhdr < (shdrs_data + sh_size)) {
470 		nnamesz  = rte_le_to_cpu_32(nhdr->n_namesz);
471 		ndescsz  = rte_le_to_cpu_32(nhdr->n_descsz);
472 		ntype    = rte_le_to_cpu_32(nhdr->n_type);
473 		nname    = (const char *)((uint8_t *)nhdr + sizeof(*nhdr));
474 		descword = (rte_le32_t *)((uint8_t *)nhdr + sizeof(*nhdr) +
475 				((nnamesz + UINT32_C(3)) & ~UINT32_C(3)));
476 
477 		err = nfp_elf_parse_note_name_nfp(ectx, idx, ndescsz, ntype, nname, descword);
478 		if (err != 0)
479 			return err;
480 
481 		nhdr = (struct nfp_elf_elf64_nhdr *)((uint8_t *)descword +
482 				((ndescsz + UINT32_C(3)) & ~UINT32_C(3)));
483 	}
484 
485 	if (ectx->user_note_cnt == 0)
486 		return 0;
487 
488 	ectx->user_notes = calloc(ectx->user_note_cnt, sizeof(*ectx->user_notes));
489 	if (ectx->user_notes == NULL) {
490 		PMD_DRV_LOG(ERR, "Out of memory.");
491 		return -ENOMEM;
492 	}
493 
494 	nhdr = (struct nfp_elf_elf64_nhdr *)shdrs_data;
495 	unote = ectx->user_notes;
496 	while ((uint8_t *)nhdr < (shdrs_data + sh_size)) {
497 		nnamesz = rte_le_to_cpu_32(nhdr->n_namesz);
498 		ndescsz = rte_le_to_cpu_32(nhdr->n_descsz);
499 		ntype   = rte_le_to_cpu_32(nhdr->n_type);
500 		nname   = (const char *)((uint8_t *)nhdr + sizeof(*nhdr));
501 		desc    = (uint8_t *)nhdr + sizeof(*nhdr) +
502 				((nnamesz + UINT32_C(3)) & ~UINT32_C(3));
503 
504 		if (strncmp(nname, NFP_ELT_NOTE_NAME_NFP_USER,
505 				NFP_ELT_NOTE_NAME_NFP_USER_SZ) != 0)
506 			continue;
507 
508 		if (ntype != NFP_ELF_NT_NFP_USER)
509 			continue;
510 
511 		unote->name = (const char *)desc;
512 		nsz = strlen(unote->name) + 1;
513 		if (nsz % 4 != 0)
514 			nsz = ((nsz / 4) + 1) * 4;
515 		if (nsz > ndescsz) {
516 			PMD_DRV_LOG(ERR, "Invalid ELF USER NOTE descsz in section %zu.", idx);
517 			return -EINVAL;
518 		}
519 
520 		unote->data_sz = ndescsz - (uint32_t)nsz;
521 		if (unote->data_sz != 0)
522 			unote->data = desc + nsz;
523 		unote++;
524 
525 		nhdr = (struct nfp_elf_elf64_nhdr *)
526 				(desc + ((ndescsz + UINT32_C(3)) & ~UINT32_C(3)));
527 	}
528 
529 	return 0;
530 }
531 
532 static int
533 nfp_elf_parse_sht_meconfig(struct nfp_elf_elf64_shdr *sec,
534 		struct nfp_elf *ectx,
535 		size_t idx,
536 		uint8_t *buf8)
537 {
538 	size_t ent_cnt;
539 	uint8_t *shdrs_data;
540 	uint64_t sh_size = rte_le_to_cpu_64(sec->sh_size);
541 	uint64_t sh_offset = rte_le_to_cpu_64(sec->sh_offset);
542 
543 	if (!nfp_elf_check_sh_size(sh_size)) {
544 		PMD_DRV_LOG(ERR, "Invalid ELF section header, index %zu.", idx);
545 		return -EINVAL;
546 	}
547 
548 	shdrs_data = buf8 + sh_offset;
549 	ent_cnt = nfp_elf_get_sec_ent_cnt(ectx, idx);
550 	ectx->shdrs_data[idx] = shdrs_data;
551 	ectx->meconfs = (struct nfp_elf_elf_meconfig *)shdrs_data;
552 	ectx->meconfs_cnt = ent_cnt;
553 	ectx->shdrs_host_endian[idx] = 1;
554 
555 	return 0;
556 }
557 
558 static int
559 nfp_elf_parse_sht_initreg(struct nfp_elf_elf64_shdr *sec,
560 		struct nfp_elf *ectx,
561 		size_t idx,
562 		uint8_t *buf8)
563 {
564 	uint64_t sh_size = rte_le_to_cpu_64(sec->sh_size);
565 	uint64_t sh_offset = rte_le_to_cpu_64(sec->sh_offset);
566 	uint64_t sh_entsize = rte_le_to_cpu_64(sec->sh_entsize);
567 
568 	if (!nfp_elf_arch_is_thornham(ectx)) {
569 		PMD_DRV_LOG(ERR, "Section not supported for target arch.");
570 		return -ENOTSUP;
571 	}
572 
573 	if (sh_entsize != sizeof(struct nfp_elf_elf_initregentry) ||
574 			!nfp_elf_check_sh_size(sh_size)) {
575 		PMD_DRV_LOG(ERR, "Invalid ELF section header, index %zu.", idx);
576 		return -EINVAL;
577 	}
578 
579 	ectx->shdrs_data[idx] = buf8 + sh_offset;
580 	ectx->shdrs_host_endian[idx] = 1;
581 
582 	return 0;
583 }
584 
585 static int
586 nfp_elf_parse_sht_symtab(struct nfp_elf_elf64_shdr *sec,
587 		struct nfp_elf *ectx,
588 		size_t idx,
589 		uint8_t *buf8)
590 {
591 	uint64_t sh_size = rte_le_to_cpu_64(sec->sh_size);
592 	uint64_t sh_offset = rte_le_to_cpu_64(sec->sh_offset);
593 	uint64_t sh_entsize = rte_le_to_cpu_64(sec->sh_entsize);
594 
595 	if (sh_entsize != sizeof(struct nfp_elf_elf64_sym) ||
596 			!nfp_elf_check_sh_size(sh_size)) {
597 		PMD_DRV_LOG(ERR, "Invalid ELF section header, index %zu.", idx);
598 		return -EINVAL;
599 	}
600 
601 	ectx->shdrs_data[idx] = buf8 + sh_offset;
602 	ectx->shdrs_host_endian[ectx->shdr_idx_symtab] = 1;
603 
604 	return 0;
605 }
606 
607 static int
608 nfp_elf_populate_fw_mip(struct nfp_elf *ectx,
609 		uint8_t *buf8)
610 {
611 	uint8_t *pu8;
612 	const char *nx;
613 	uint64_t sh_size;
614 	uint64_t sh_offset;
615 	uint32_t first_entry;
616 	const struct nfp_mip *mip;
617 	struct nfp_elf_elf64_shdr *sec;
618 	const struct nfp_mip_entry *ent;
619 	const struct nfp_mip_fwinfo_entry *fwinfo;
620 
621 	sec = &ectx->shdrs[ectx->mip_shndx];
622 	sh_size = rte_le_to_cpu_64(sec->sh_size);
623 	sh_offset = rte_le_to_cpu_64(sec->sh_offset);
624 	pu8 = buf8 + sh_offset + ectx->mip_sh_off;
625 	mip = (const struct nfp_mip *)pu8;
626 	first_entry = rte_le_to_cpu_32(mip->first_entry);
627 
628 	if (mip->signature != NFP_MIP_SIGNATURE) {
629 		PMD_DRV_LOG(ERR, "Incorrect MIP signature %#08x",
630 				rte_le_to_cpu_32(mip->signature));
631 		return -EINVAL;
632 	}
633 
634 	ectx->fw_mip.shndx = ectx->mip_shndx;
635 	ectx->fw_mip.sh_offset = ectx->mip_sh_off;
636 	ectx->fw_mip.mip_ver = mip->mip_version;
637 
638 	if (ectx->fw_mip.mip_ver != NFP_MIP_VERSION) {
639 		PMD_DRV_LOG(ERR, "MIP note pointer does not point to recognised version.");
640 		return -EINVAL;
641 	}
642 
643 	ectx->fw_mip.fw_version   = mip->version;
644 	ectx->fw_mip.fw_buildnum  = mip->buildnum;
645 	ectx->fw_mip.fw_buildtime = mip->buildtime;
646 	strncpy(ectx->fw_mip.fw_name, mip->name, 16);
647 
648 	/*
649 	 * If there is a FWINFO v1 entry, it will be first and
650 	 * right after the MIP itself, so in the same section.
651 	 */
652 	if (ectx->mip_sh_off + first_entry + sizeof(*ent) < sh_size) {
653 		pu8 += first_entry;
654 		ent = (const struct nfp_mip_entry *)pu8;
655 		if (ent->type == NFP_MIP_TYPE_FWINFO && ent->version == 1) {
656 			pu8 += sizeof(*ent);
657 			fwinfo = (const struct nfp_mip_fwinfo_entry *)pu8;
658 			if (fwinfo->kv_len != 0) {
659 				ectx->fw_info_strtab_sz = fwinfo->kv_len;
660 				ectx->fw_info_strtab = fwinfo->key_value_strs;
661 			}
662 		}
663 	}
664 
665 	ectx->fw_mip.fw_typeid = nfp_elf_fwinfo_lookup(ectx, "TypeId");
666 
667 	/*
668 	 * TypeId will be the last reserved key-value pair, so skip
669 	 * to the first entry after it for the user values.
670 	 */
671 	if (ectx->fw_mip.fw_typeid == NULL)
672 		return 0;
673 
674 	nx = nfp_elf_fwinfo_next(ectx, ectx->fw_mip.fw_typeid);
675 	if (nx == NULL)
676 		ectx->fw_info_strtab_sz = 0;
677 	else
678 		ectx->fw_info_strtab_sz -= (nx - ectx->fw_info_strtab);
679 	ectx->fw_info_strtab = nx;
680 
681 	return 0;
682 }
683 
684 static int
685 nfp_elf_read_file_headers(struct nfp_elf *ectx,
686 		void *buf)
687 {
688 	uint16_t e_type;
689 	uint32_t e_flags;
690 	uint32_t e_version;
691 	uint16_t e_machine;
692 
693 	ectx->ehdr = buf;
694 	e_type = rte_le_to_cpu_16(ectx->ehdr->e_type);
695 	e_flags = rte_le_to_cpu_32(ectx->ehdr->e_flags);
696 	e_version = rte_le_to_cpu_32(ectx->ehdr->e_version);
697 	e_machine = rte_le_to_cpu_16(ectx->ehdr->e_machine);
698 
699 	switch (e_machine) {
700 	case NFP_ELF_EM_NFP:
701 		ectx->family = (e_flags >> NFP_ELF_EF_NFP_FAMILY_LSB)
702 				& NFP_ELF_EF_NFP_FAMILY_MASK;
703 		break;
704 	case NFP_ELF_EM_NFP6000:
705 		ectx->family = NFP_CHIP_FAMILY_NFP6000;
706 		break;
707 	default:
708 		PMD_DRV_LOG(ERR, "Invalid ELF machine type.");
709 		return -EINVAL;
710 	}
711 
712 	if ((e_type != NFP_ELF_ET_EXEC && e_type != NFP_ELF_ET_REL &&
713 			e_type != NFP_ELF_ET_NFP_PARTIAL_EXEC &&
714 			e_type != NFP_ELF_ET_NFP_PARTIAL_REL) ||
715 			e_version != NFP_ELF_EV_CURRENT ||
716 			ectx->ehdr->e_ehsize != sizeof(struct nfp_elf_elf64_ehdr) ||
717 			ectx->ehdr->e_shentsize != sizeof(struct nfp_elf_elf64_shdr)) {
718 		PMD_DRV_LOG(ERR, "Invalid ELF file header.");
719 		return -EINVAL;
720 	}
721 
722 	if (ectx->ehdr->e_shoff < ectx->ehdr->e_ehsize) {
723 		PMD_DRV_LOG(ERR, "Invalid ELF header content.");
724 		return -EINVAL;
725 	}
726 
727 	if (ectx->ehdr->e_shstrndx >= ectx->ehdr->e_shnum) {
728 		PMD_DRV_LOG(ERR, "Invalid ELF header content.");
729 		return -EINVAL;
730 	}
731 
732 	return 0;
733 }
734 
735 static int
736 nfp_elf_read_section_headers(struct nfp_elf *ectx,
737 		uint8_t *buf8,
738 		size_t buf_len)
739 {
740 	size_t idx;
741 	int err = 0;
742 	uint8_t *pu8;
743 	uint64_t sh_size;
744 	uint64_t sh_offset;
745 	uint64_t sh_entsize;
746 	struct nfp_elf_elf64_shdr *sec;
747 	uint64_t e_shoff = rte_le_to_cpu_16(ectx->ehdr->e_shoff);
748 	uint16_t e_shnum = rte_le_to_cpu_16(ectx->ehdr->e_shnum);
749 
750 	if (buf_len < e_shoff + ((size_t)e_shnum * sizeof(*sec))) {
751 		PMD_DRV_LOG(ERR, "ELF data too short.");
752 		return -EINVAL;
753 	}
754 
755 	pu8 = buf8 + e_shoff;
756 
757 	if (e_shnum == 0) {
758 		ectx->shdrs = NULL;
759 		ectx->shdrs_data = NULL;
760 		ectx->shdrs_host_endian = NULL;
761 		ectx->shdrs_cnt = 0;
762 		return 0;
763 	}
764 
765 	ectx->shdrs = calloc(e_shnum, sizeof(*ectx->shdrs));
766 	if (ectx->shdrs == NULL) {
767 		PMD_DRV_LOG(ERR, "Out of memory.");
768 		return -ENOMEM;
769 	}
770 
771 	ectx->shdrs_data = calloc(e_shnum, sizeof(void *));
772 	if (ectx->shdrs_data == NULL) {
773 		PMD_DRV_LOG(ERR, "Out of memory.");
774 		err = -ENOMEM;
775 		goto free_shdrs;
776 	}
777 
778 	ectx->shdrs_host_endian = calloc(e_shnum, sizeof(ectx->shdrs_host_endian[0]));
779 	if (ectx->shdrs_host_endian == NULL) {
780 		PMD_DRV_LOG(ERR, "Out of memory.");
781 		err = -ENOMEM;
782 		goto free_shdrs_data;
783 	}
784 
785 	memcpy(ectx->shdrs, pu8, e_shnum * sizeof(*ectx->shdrs));
786 	ectx->shdrs_cnt = e_shnum;
787 
788 	for (idx = 0, sec = ectx->shdrs; idx < ectx->shdrs_cnt; idx++, sec++) {
789 		sh_size = rte_le_to_cpu_64(sec->sh_size);
790 		sh_offset = rte_le_to_cpu_64(sec->sh_offset);
791 		sh_entsize = rte_le_to_cpu_64(sec->sh_entsize);
792 
793 		if (sh_entsize != 0 && (sh_size % sh_entsize != 0)) {
794 			PMD_DRV_LOG(ERR, "Invalid ELF section header, index %zu.", idx);
795 			err = -EINVAL;
796 			goto free_shdrs_host_endian;
797 		}
798 
799 		switch (rte_le_to_cpu_32(sec->sh_type)) {
800 		case NFP_ELF_SHT_REL:
801 			err = nfp_elf_parse_sht_rel(sec, ectx, idx, buf8);
802 			if (err != 0) {
803 				PMD_DRV_LOG(ERR, "Failed to parse sht rel.");
804 				goto free_shdrs_host_endian;
805 			}
806 			break;
807 		case NFP_ELF_SHT_NOTE:
808 			err = nfp_elf_parse_sht_note(sec, ectx, idx, buf8);
809 			if (err != 0) {
810 				PMD_DRV_LOG(ERR, "Failed to parse sht note.");
811 				goto free_shdrs_host_endian;
812 			}
813 			break;
814 		case NFP_ELF_SHT_NFP_MECONFIG:
815 			err = nfp_elf_parse_sht_meconfig(sec, ectx, idx, buf8);
816 			if (err != 0) {
817 				PMD_DRV_LOG(ERR, "Failed to parse sht meconfig.");
818 				goto free_shdrs_host_endian;
819 			}
820 			break;
821 		case NFP_ELF_SHT_NFP_INITREG:
822 			err = nfp_elf_parse_sht_initreg(sec, ectx, idx, buf8);
823 			if (err != 0) {
824 				PMD_DRV_LOG(ERR, "Failed to parse sht initregp.");
825 				goto free_shdrs_host_endian;
826 			}
827 			break;
828 		case NFP_ELF_SHT_SYMTAB:
829 			err = nfp_elf_parse_sht_symtab(sec, ectx, idx, buf8);
830 			if (err != 0) {
831 				PMD_DRV_LOG(ERR, "Failed to parse sht symtab.");
832 				goto free_shdrs_host_endian;
833 			}
834 			break;
835 		case NFP_ELF_SHT_NOBITS:
836 		case NFP_ELF_SHT_NULL:
837 			break;
838 		default:
839 			if (sh_offset > 0 && sh_size <= 0)
840 				break;
841 
842 			/*
843 			 * Limit sections to 4GiB, because they won't need to be this large
844 			 * and this ensures we can handle the file on 32-bit hosts without
845 			 * unexpected problems.
846 			 */
847 			if (sh_size > UINT32_MAX) {
848 				PMD_DRV_LOG(ERR, "Invalid ELF section header, index %zu.", idx);
849 				err = -EINVAL;
850 				goto free_shdrs_host_endian;
851 			}
852 
853 			pu8 = buf8 + sh_offset;
854 			ectx->shdrs_data[idx] = pu8;
855 			ectx->shdrs_host_endian[idx] = 0;
856 			break;
857 		}
858 	}
859 
860 	return 0;
861 
862 free_shdrs_host_endian:
863 	free(ectx->shdrs_host_endian);
864 free_shdrs_data:
865 	free(ectx->shdrs_data);
866 free_shdrs:
867 	free(ectx->shdrs);
868 
869 	return err;
870 }
871 
872 static int
873 nfp_elf_read_shstrtab(struct nfp_elf *ectx)
874 {
875 	struct nfp_elf_elf64_shdr *sec;
876 	uint16_t e_shstrndx = rte_le_to_cpu_16(ectx->ehdr->e_shstrndx);
877 
878 	if (ectx->ehdr->e_shnum <= ectx->ehdr->e_shstrndx) {
879 		PMD_DRV_LOG(ERR, "Invalid Index.");
880 		return -EINVAL;
881 	}
882 
883 	sec = &ectx->shdrs[e_shstrndx];
884 	if (sec == NULL || rte_le_to_cpu_32(sec->sh_type) != NFP_ELF_SHT_STRTAB) {
885 		PMD_DRV_LOG(ERR, "Invalid ELF shstrtab.");
886 		return -EINVAL;
887 	}
888 
889 	ectx->shstrtab = ectx->shdrs_data[e_shstrndx];
890 	ectx->shstrtab_sz = rte_le_to_cpu_64(sec->sh_size);
891 
892 	return 0;
893 }
894 
895 static int
896 nfp_elf_read_first_symtab(struct nfp_elf *ectx)
897 {
898 	size_t idx;
899 	uint32_t sh_type;
900 	uint64_t sh_size;
901 	struct nfp_elf_elf64_shdr *sec;
902 
903 	for (idx = 0, sec = ectx->shdrs; idx < ectx->shdrs_cnt; idx++, sec++) {
904 		if (sec != NULL) {
905 			sh_type = rte_le_to_cpu_32(sec->sh_type);
906 			if (sh_type == NFP_ELF_SHT_SYMTAB)
907 				break;
908 		}
909 	}
910 
911 	sh_size = rte_le_to_cpu_64(sec->sh_size);
912 
913 	if (idx < ectx->shdrs_cnt && sh_type == NFP_ELF_SHT_SYMTAB) {
914 		ectx->shdr_idx_symtab = idx;
915 		ectx->syms = ectx->shdrs_data[idx];
916 		ectx->syms_cnt = nfp_elf_get_sec_ent_cnt(ectx, idx);
917 
918 		/* Load symtab's strtab */
919 		idx = rte_le_to_cpu_32(sec->sh_link);
920 
921 		if (idx == NFP_ELF_SHN_UNDEF || idx >= ectx->shdrs_cnt) {
922 			PMD_DRV_LOG(ERR, "ELF symtab has no strtab.");
923 			return -EINVAL;
924 		}
925 
926 		sec = &ectx->shdrs[idx];
927 		sh_type = rte_le_to_cpu_32(sec->sh_type);
928 		if (sh_type != NFP_ELF_SHT_STRTAB) {
929 			PMD_DRV_LOG(ERR, "ELF symtab has no strtab.");
930 			return -EINVAL;
931 		}
932 
933 		if (!nfp_elf_check_sh_size(sh_size)) {
934 			PMD_DRV_LOG(ERR, "ELF symtab has invalid strtab.");
935 			return -EINVAL;
936 		}
937 
938 		ectx->symstrtab = ectx->shdrs_data[idx];
939 		ectx->symstrtab_sz = sh_size;
940 	}
941 
942 	return 0;
943 }
944 
945 static int
946 nfp_elf_is_valid_file(uint8_t *buf8)
947 {
948 	if (buf8[NFP_ELF_EI_MAG0] != NFP_ELF_ELFMAG0 ||
949 			buf8[NFP_ELF_EI_MAG1] != NFP_ELF_ELFMAG1 ||
950 			buf8[NFP_ELF_EI_MAG2] != NFP_ELF_ELFMAG2 ||
951 			buf8[NFP_ELF_EI_MAG3] != NFP_ELF_ELFMAG3 ||
952 			buf8[NFP_ELF_EI_VERSION] != NFP_ELF_EV_CURRENT ||
953 			buf8[NFP_ELF_EI_DATA] != NFP_ELF_ELFDATA2LSB)
954 		return -EINVAL;
955 
956 	return 0;
957 }
958 
959 static int
960 nfp_elf_is_valid_class(uint8_t *buf8)
961 {
962 	if (buf8[NFP_ELF_EI_CLASS] != NFP_ELF_ELFCLASS64)
963 		return -EINVAL;
964 
965 	return 0;
966 }
967 
968 static struct nfp_elf *
969 nfp_elf_mutable_buf(void *buf,
970 		size_t buf_len)
971 {
972 	int err = 0;
973 	uint8_t *buf8 = buf;
974 	struct nfp_elf *ectx;
975 
976 	if (buf == NULL) {
977 		PMD_DRV_LOG(ERR, "Invalid parameters.");
978 		return NULL;
979 	}
980 
981 	if (buf_len < sizeof(struct nfp_elf_elf64_ehdr)) {
982 		PMD_DRV_LOG(ERR, "ELF data too short.");
983 		return NULL;
984 	}
985 
986 	ectx = calloc(1, sizeof(struct nfp_elf));
987 	if (ectx == NULL) {
988 		PMD_DRV_LOG(ERR, "Out of memory.");
989 		return NULL;
990 	}
991 
992 	ectx->rev_min = -1;
993 	ectx->rev_max = -1;
994 	ectx->mip_sh_off = UINT64_MAX;
995 
996 	err = nfp_elf_is_valid_file(buf8);
997 	if (err != 0) {
998 		PMD_DRV_LOG(ERR, "Not a valid ELF file.");
999 		goto elf_free;
1000 	}
1001 
1002 	err = nfp_elf_is_valid_class(buf8);
1003 	if (err != 0) {
1004 		PMD_DRV_LOG(ERR, "Unknown ELF class.");
1005 		goto elf_free;
1006 	}
1007 
1008 	err = nfp_elf_read_file_headers(ectx, buf);
1009 	if (err != 0) {
1010 		PMD_DRV_LOG(ERR, "Failed to read file headers.");
1011 		goto elf_free;
1012 	}
1013 
1014 	err = nfp_elf_read_section_headers(ectx, buf8, buf_len);
1015 	if (err != 0) {
1016 		PMD_DRV_LOG(ERR, "Failed to read section headers.");
1017 		goto elf_free;
1018 	}
1019 
1020 	err = nfp_elf_read_shstrtab(ectx);
1021 	if (err != 0) {
1022 		PMD_DRV_LOG(ERR, "Failed to read shstrtab.");
1023 		goto elf_free;
1024 	}
1025 
1026 	/* Read first symtab if any, assuming it's the primary or only one */
1027 	err = nfp_elf_read_first_symtab(ectx);
1028 	if (err != 0) {
1029 		PMD_DRV_LOG(ERR, "Failed to read first symtab.");
1030 		goto elf_free;
1031 	}
1032 
1033 	/* Populate the fw_mip struct if we have a .note for it */
1034 	if (ectx->mip_shndx != 0) {
1035 		err = nfp_elf_populate_fw_mip(ectx, buf8);
1036 		if (err != 0) {
1037 			PMD_DRV_LOG(ERR, "Failed to populate the fw mip.");
1038 			goto elf_free;
1039 		}
1040 	}
1041 
1042 	ectx->_buf = buf;
1043 	ectx->_bufsz = 0;
1044 
1045 	return ectx;
1046 
1047 elf_free:
1048 	nfp_elf_free(ectx);
1049 
1050 	return NULL;
1051 }
1052 
1053 int
1054 nfp_elf_get_fw_version(uint32_t *fw_version,
1055 		char *fw_name)
1056 {
1057 	void *fw_buf;
1058 	size_t fsize;
1059 	struct nfp_elf *elf;
1060 
1061 	if (rte_firmware_read(fw_name, &fw_buf, &fsize) != 0) {
1062 		PMD_DRV_LOG(ERR, "firmware %s not found!", fw_name);
1063 		return -ENOENT;
1064 	}
1065 
1066 	elf = nfp_elf_mutable_buf(fw_buf, fsize);
1067 	if (elf == NULL) {
1068 		PMD_DRV_LOG(ERR, "Parse nffw file failed.");
1069 		free(fw_buf);
1070 		return -EIO;
1071 	}
1072 
1073 	*fw_version = rte_le_to_cpu_32(elf->fw_mip.fw_version);
1074 
1075 	nfp_elf_free(elf);
1076 	free(fw_buf);
1077 	return 0;
1078 }
1079 
1080