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