1 /*
2 * Copyright (c) 2014, Mentor Graphics Corporation
3 * All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 #include <string.h>
9 #include <metal/alloc.h>
10 #include <metal/log.h>
11 #include <openamp/elf_loader.h>
12 #include <openamp/remoteproc.h>
13
elf_is_64(const void * elf_info)14 static int elf_is_64(const void *elf_info)
15 {
16 const unsigned char *tmp = elf_info;
17
18 if (tmp[EI_CLASS] == ELFCLASS64)
19 return 1;
20 else
21 return 0;
22 }
23
elf_ehdr_size(const void * elf_info)24 static size_t elf_ehdr_size(const void *elf_info)
25 {
26 if (!elf_info)
27 return sizeof(Elf64_Ehdr);
28 else if (elf_is_64(elf_info) != 0)
29 return sizeof(Elf64_Ehdr);
30 else
31 return sizeof(Elf32_Ehdr);
32 }
33
elf_phoff(const void * elf_info)34 static size_t elf_phoff(const void *elf_info)
35 {
36 if (elf_is_64(elf_info) == 0) {
37 const Elf32_Ehdr *ehdr = elf_info;
38
39 return ehdr->e_phoff;
40 } else {
41 const Elf64_Ehdr *ehdr = elf_info;
42
43 return ehdr->e_phoff;
44 }
45 }
46
elf_phentsize(const void * elf_info)47 static size_t elf_phentsize(const void *elf_info)
48 {
49 if (elf_is_64(elf_info) == 0) {
50 const Elf32_Ehdr *ehdr = elf_info;
51
52 return ehdr->e_phentsize;
53 } else {
54 const Elf64_Ehdr *ehdr = elf_info;
55
56 return ehdr->e_phentsize;
57 }
58 }
59
elf_phnum(const void * elf_info)60 static int elf_phnum(const void *elf_info)
61 {
62 if (elf_is_64(elf_info) == 0) {
63 const Elf32_Ehdr *ehdr = elf_info;
64
65 return ehdr->e_phnum;
66 } else {
67 const Elf64_Ehdr *ehdr = elf_info;
68
69 return ehdr->e_phnum;
70 }
71 }
72
elf_shoff(const void * elf_info)73 static size_t elf_shoff(const void *elf_info)
74 {
75 if (elf_is_64(elf_info) == 0) {
76 const Elf32_Ehdr *ehdr = elf_info;
77
78 return ehdr->e_shoff;
79 } else {
80 const Elf64_Ehdr *ehdr = elf_info;
81
82 return ehdr->e_shoff;
83 }
84 }
85
elf_shentsize(const void * elf_info)86 static size_t elf_shentsize(const void *elf_info)
87 {
88 if (elf_is_64(elf_info) == 0) {
89 const Elf32_Ehdr *ehdr = elf_info;
90
91 return ehdr->e_shentsize;
92 } else {
93 const Elf64_Ehdr *ehdr = elf_info;
94
95 return ehdr->e_shentsize;
96 }
97 }
98
elf_shnum(const void * elf_info)99 static int elf_shnum(const void *elf_info)
100 {
101 if (elf_is_64(elf_info) == 0) {
102 const Elf32_Ehdr *ehdr = elf_info;
103
104 return ehdr->e_shnum;
105 } else {
106 const Elf64_Ehdr *ehdr = elf_info;
107
108 return ehdr->e_shnum;
109 }
110 }
111
elf_shstrndx(const void * elf_info)112 static int elf_shstrndx(const void *elf_info)
113 {
114 if (elf_is_64(elf_info) == 0) {
115 const Elf32_Ehdr *ehdr = elf_info;
116
117 return ehdr->e_shstrndx;
118 } else {
119 const Elf64_Ehdr *ehdr = elf_info;
120
121 return ehdr->e_shstrndx;
122 }
123 }
124
elf_phtable_ptr(void * elf_info)125 static void **elf_phtable_ptr(void *elf_info)
126 {
127 if (elf_is_64(elf_info) == 0) {
128 struct elf32_info *einfo = elf_info;
129
130 return (void **)&einfo->phdrs;
131 } else {
132 struct elf64_info *einfo = elf_info;
133
134 return (void **)&einfo->phdrs;
135 }
136 }
137
elf_shtable_ptr(void * elf_info)138 static void **elf_shtable_ptr(void *elf_info)
139 {
140 if (elf_is_64(elf_info) == 0) {
141 struct elf32_info *einfo = elf_info;
142
143 return (void **)&einfo->shdrs;
144 } else {
145 struct elf64_info *einfo = elf_info;
146
147 return (void **)&einfo->shdrs;
148 }
149 }
150
elf_shstrtab_ptr(void * elf_info)151 static void **elf_shstrtab_ptr(void *elf_info)
152 {
153 if (elf_is_64(elf_info) == 0) {
154 struct elf32_info *einfo = elf_info;
155
156 return &einfo->shstrtab;
157 } else {
158 struct elf64_info *einfo = elf_info;
159
160 return &einfo->shstrtab;
161 }
162 }
163
elf_load_state(void * elf_info)164 static int *elf_load_state(void *elf_info)
165 {
166 if (elf_is_64(elf_info) == 0) {
167 struct elf32_info *einfo = elf_info;
168
169 return &einfo->load_state;
170 } else {
171 struct elf64_info *einfo = elf_info;
172
173 return &einfo->load_state;
174 }
175 }
176
elf_parse_segment(void * elf_info,const void * elf_phdr,unsigned int * p_type,size_t * p_offset,metal_phys_addr_t * p_vaddr,metal_phys_addr_t * p_paddr,size_t * p_filesz,size_t * p_memsz)177 static void elf_parse_segment(void *elf_info, const void *elf_phdr,
178 unsigned int *p_type, size_t *p_offset,
179 metal_phys_addr_t *p_vaddr,
180 metal_phys_addr_t *p_paddr,
181 size_t *p_filesz, size_t *p_memsz)
182 {
183 if (elf_is_64(elf_info) == 0) {
184 const Elf32_Phdr *phdr = elf_phdr;
185
186 if (p_type)
187 *p_type = (unsigned int)phdr->p_type;
188 if (p_offset)
189 *p_offset = (size_t)phdr->p_offset;
190 if (p_vaddr)
191 *p_vaddr = (metal_phys_addr_t)phdr->p_vaddr;
192 if (p_paddr)
193 *p_paddr = (metal_phys_addr_t)phdr->p_paddr;
194 if (p_filesz)
195 *p_filesz = (size_t)phdr->p_filesz;
196 if (p_memsz)
197 *p_memsz = (size_t)phdr->p_memsz;
198 } else {
199 const Elf64_Phdr *phdr = elf_phdr;
200
201 if (p_type)
202 *p_type = (unsigned int)phdr->p_type;
203 if (p_offset)
204 *p_offset = (size_t)phdr->p_offset;
205 if (p_vaddr)
206 *p_vaddr = (metal_phys_addr_t)phdr->p_vaddr;
207 if (p_paddr)
208 *p_paddr = (metal_phys_addr_t)phdr->p_paddr;
209 if (p_filesz)
210 *p_filesz = (size_t)phdr->p_filesz;
211 if (p_memsz)
212 *p_memsz = (size_t)phdr->p_memsz;
213 }
214 }
215
elf_get_segment_from_index(void * elf_info,int index)216 static const void *elf_get_segment_from_index(void *elf_info, int index)
217 {
218 if (elf_is_64(elf_info) == 0) {
219 const struct elf32_info *einfo = elf_info;
220 const Elf32_Ehdr *ehdr = &einfo->ehdr;
221 const Elf32_Phdr *phdrs = einfo->phdrs;
222
223 if (!phdrs)
224 return NULL;
225 if (index < 0 || index >= ehdr->e_phnum)
226 return NULL;
227 return &phdrs[index];
228 } else {
229 const struct elf64_info *einfo = elf_info;
230 const Elf64_Ehdr *ehdr = &einfo->ehdr;
231 const Elf64_Phdr *phdrs = einfo->phdrs;
232
233 if (!phdrs)
234 return NULL;
235 if (index < 0 || index >= ehdr->e_phnum)
236 return NULL;
237 return &phdrs[index];
238 }
239 }
240
elf_get_section_from_name(void * elf_info,const char * name)241 static void *elf_get_section_from_name(void *elf_info, const char *name)
242 {
243 unsigned int i;
244 const char *name_table;
245
246 if (elf_is_64(elf_info) == 0) {
247 struct elf32_info *einfo = elf_info;
248 Elf32_Ehdr *ehdr = &einfo->ehdr;
249 Elf32_Shdr *shdr = einfo->shdrs;
250
251 name_table = einfo->shstrtab;
252 if (!shdr || !name_table)
253 return NULL;
254 for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
255 if (strcmp(name, name_table + shdr->sh_name))
256 continue;
257 else
258 return shdr;
259 }
260 } else {
261 struct elf64_info *einfo = elf_info;
262 Elf64_Ehdr *ehdr = &einfo->ehdr;
263 Elf64_Shdr *shdr = einfo->shdrs;
264
265 name_table = einfo->shstrtab;
266 if (!shdr || !name_table)
267 return NULL;
268 for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
269 if (strcmp(name, name_table + shdr->sh_name))
270 continue;
271 else
272 return shdr;
273 }
274 }
275 return NULL;
276 }
277
elf_get_section_from_index(void * elf_info,int index)278 static void *elf_get_section_from_index(void *elf_info, int index)
279 {
280 if (elf_is_64(elf_info) == 0) {
281 struct elf32_info *einfo = elf_info;
282 Elf32_Ehdr *ehdr = &einfo->ehdr;
283 Elf32_Shdr *shdr = einfo->shdrs;
284
285 if (!shdr)
286 return NULL;
287 if (index < 0 || index >= ehdr->e_shnum)
288 return NULL;
289 return &einfo->shdrs[index];
290 } else {
291 struct elf64_info *einfo = elf_info;
292 Elf64_Ehdr *ehdr = &einfo->ehdr;
293 Elf64_Shdr *shdr = einfo->shdrs;
294
295 if (!shdr)
296 return NULL;
297 if (index < 0 || index >= ehdr->e_shnum)
298 return NULL;
299 return &einfo->shdrs[index];
300 }
301 }
302
elf_parse_section(void * elf_info,void * elf_shdr,unsigned int * sh_type,unsigned int * sh_flags,metal_phys_addr_t * sh_addr,size_t * sh_offset,size_t * sh_size,unsigned int * sh_link,unsigned int * sh_info,unsigned int * sh_addralign,size_t * sh_entsize)303 static void elf_parse_section(void *elf_info, void *elf_shdr,
304 unsigned int *sh_type, unsigned int *sh_flags,
305 metal_phys_addr_t *sh_addr,
306 size_t *sh_offset, size_t *sh_size,
307 unsigned int *sh_link, unsigned int *sh_info,
308 unsigned int *sh_addralign,
309 size_t *sh_entsize)
310 {
311 if (elf_is_64(elf_info) == 0) {
312 Elf32_Shdr *shdr = elf_shdr;
313
314 if (sh_type)
315 *sh_type = shdr->sh_type;
316 if (sh_flags)
317 *sh_flags = shdr->sh_flags;
318 if (sh_addr)
319 *sh_addr = (metal_phys_addr_t)shdr->sh_addr;
320 if (sh_offset)
321 *sh_offset = shdr->sh_offset;
322 if (sh_size)
323 *sh_size = shdr->sh_size;
324 if (sh_link)
325 *sh_link = shdr->sh_link;
326 if (sh_info)
327 *sh_info = shdr->sh_info;
328 if (sh_addralign)
329 *sh_addralign = shdr->sh_addralign;
330 if (sh_entsize)
331 *sh_entsize = shdr->sh_entsize;
332 } else {
333 Elf64_Shdr *shdr = elf_shdr;
334
335 if (sh_type)
336 *sh_type = shdr->sh_type;
337 if (sh_flags)
338 *sh_flags = shdr->sh_flags;
339 if (sh_addr)
340 *sh_addr = (metal_phys_addr_t)shdr->sh_addr;
341 if (sh_offset)
342 *sh_offset = shdr->sh_offset;
343 if (sh_size)
344 *sh_size = shdr->sh_size;
345 if (sh_link)
346 *sh_link = shdr->sh_link;
347 if (sh_info)
348 *sh_info = shdr->sh_info;
349 if (sh_addralign)
350 *sh_addralign = shdr->sh_addralign;
351 if (sh_entsize)
352 *sh_entsize = shdr->sh_entsize;
353 }
354 }
355
elf_next_load_segment(void * elf_info,int * nseg,metal_phys_addr_t * da,size_t * noffset,size_t * nfsize,size_t * nmsize)356 static const void *elf_next_load_segment(void *elf_info, int *nseg,
357 metal_phys_addr_t *da,
358 size_t *noffset, size_t *nfsize,
359 size_t *nmsize)
360 {
361 const void *phdr = PT_NULL;
362 unsigned int p_type = PT_NULL;
363
364 if (!elf_info || !nseg)
365 return NULL;
366 while (p_type != PT_LOAD) {
367 phdr = elf_get_segment_from_index(elf_info, *nseg);
368 if (!phdr)
369 return NULL;
370 elf_parse_segment(elf_info, phdr, &p_type, noffset,
371 da, NULL, nfsize, nmsize);
372 *nseg = *nseg + 1;
373 }
374 return phdr;
375 }
376
elf_info_size(const void * img_data)377 static size_t elf_info_size(const void *img_data)
378 {
379 if (elf_is_64(img_data) == 0)
380 return sizeof(struct elf32_info);
381 else
382 return sizeof(struct elf64_info);
383 }
384
elf_identify(const void * img_data,size_t len)385 int elf_identify(const void *img_data, size_t len)
386 {
387 if (len < SELFMAG || !img_data)
388 return -RPROC_EINVAL;
389 if (memcmp(img_data, ELFMAG, SELFMAG) != 0)
390 return -RPROC_EINVAL;
391 else
392 return 0;
393 }
394
elf_load_header(const void * img_data,size_t offset,size_t len,void ** img_info,int last_load_state,size_t * noffset,size_t * nlen)395 int elf_load_header(const void *img_data, size_t offset, size_t len,
396 void **img_info, int last_load_state,
397 size_t *noffset, size_t *nlen)
398 {
399 int *load_state;
400
401 metal_assert(noffset);
402 metal_assert(nlen);
403 /* Get ELF header */
404 if (last_load_state == ELF_STATE_INIT) {
405 size_t tmpsize;
406
407 metal_log(METAL_LOG_DEBUG, "Loading ELF headering\r\n");
408 tmpsize = elf_ehdr_size(img_data);
409 if (len < tmpsize) {
410 *noffset = 0;
411 *nlen = tmpsize;
412 return ELF_STATE_INIT;
413 } else {
414 size_t infosize = elf_info_size(img_data);
415
416 if (!*img_info) {
417 *img_info = metal_allocate_memory(infosize);
418 if (!*img_info)
419 return -RPROC_ENOMEM;
420 memset(*img_info, 0, infosize);
421 }
422 memcpy(*img_info, img_data, tmpsize);
423 load_state = elf_load_state(*img_info);
424 *load_state = ELF_STATE_WAIT_FOR_PHDRS;
425 last_load_state = ELF_STATE_WAIT_FOR_PHDRS;
426 }
427 }
428 metal_assert(*img_info);
429 load_state = elf_load_state(*img_info);
430 if (last_load_state != *load_state)
431 return -RPROC_EINVAL;
432 /* Get ELF program headers */
433 if (*load_state == ELF_STATE_WAIT_FOR_PHDRS) {
434 size_t phdrs_size;
435 size_t phdrs_offset;
436 void **phdrs;
437 const void *img_phdrs;
438
439 metal_log(METAL_LOG_DEBUG, "Loading ELF program header.\r\n");
440 phdrs_offset = elf_phoff(*img_info);
441 phdrs_size = elf_phnum(*img_info) * elf_phentsize(*img_info);
442 if (offset > phdrs_offset ||
443 offset + len < phdrs_offset + phdrs_size) {
444 *noffset = phdrs_offset;
445 *nlen = phdrs_size;
446 return *load_state;
447 }
448 /* calculate the programs headers offset to the image_data */
449 phdrs_offset -= offset;
450 img_phdrs = (const char *)img_data + phdrs_offset;
451 phdrs = elf_phtable_ptr(*img_info);
452 *phdrs = metal_allocate_memory(phdrs_size);
453 if (!*phdrs)
454 return -RPROC_ENOMEM;
455 memcpy(*phdrs, img_phdrs, phdrs_size);
456 *load_state = ELF_STATE_WAIT_FOR_SHDRS |
457 RPROC_LOADER_READY_TO_LOAD;
458 }
459 /* Get ELF Section Headers */
460 if ((*load_state & ELF_STATE_WAIT_FOR_SHDRS) != 0) {
461 size_t shdrs_size;
462 size_t shdrs_offset;
463 void **shdrs;
464 const void *img_shdrs;
465
466 metal_log(METAL_LOG_DEBUG, "Loading ELF section header.\r\n");
467 shdrs_offset = elf_shoff(*img_info);
468 if (elf_shnum(*img_info) == 0) {
469 *load_state = (*load_state & (~ELF_STATE_MASK)) |
470 ELF_STATE_HDRS_COMPLETE;
471 *nlen = 0;
472 return *load_state;
473 }
474 shdrs_size = elf_shnum(*img_info) * elf_shentsize(*img_info);
475 if (offset > shdrs_offset ||
476 offset + len < shdrs_offset + shdrs_size) {
477 *noffset = shdrs_offset;
478 *nlen = shdrs_size;
479 return *load_state;
480 }
481 /* calculate the sections headers offset to the image_data */
482 shdrs_offset -= offset;
483 img_shdrs = (const char *)img_data + shdrs_offset;
484 shdrs = elf_shtable_ptr(*img_info);
485 *shdrs = metal_allocate_memory(shdrs_size);
486 if (!*shdrs)
487 return -RPROC_ENOMEM;
488 memcpy(*shdrs, img_shdrs, shdrs_size);
489 *load_state = (*load_state & (~ELF_STATE_MASK)) |
490 ELF_STATE_WAIT_FOR_SHSTRTAB;
491 metal_log(METAL_LOG_DEBUG,
492 "Loading ELF section header complete.\r\n");
493 }
494 /* Get ELF SHSTRTAB section */
495 if ((*load_state & ELF_STATE_WAIT_FOR_SHSTRTAB) != 0) {
496 size_t shstrtab_size;
497 size_t shstrtab_offset;
498 int shstrndx;
499 void *shdr;
500 void **shstrtab;
501
502 metal_log(METAL_LOG_DEBUG, "Loading ELF shstrtab.\r\n");
503 shstrndx = elf_shstrndx(*img_info);
504 shdr = elf_get_section_from_index(*img_info, shstrndx);
505 if (!shdr)
506 return -RPROC_EINVAL;
507 elf_parse_section(*img_info, shdr, NULL, NULL,
508 NULL, &shstrtab_offset,
509 &shstrtab_size, NULL, NULL,
510 NULL, NULL);
511 if (offset > shstrtab_offset ||
512 offset + len < shstrtab_offset + shstrtab_size) {
513 *noffset = shstrtab_offset;
514 *nlen = shstrtab_size;
515 return *load_state;
516 }
517 /* Calculate shstrtab section offset to the input image data */
518 shstrtab_offset -= offset;
519 shstrtab = elf_shstrtab_ptr(*img_info);
520 *shstrtab = metal_allocate_memory(shstrtab_size);
521 if (!*shstrtab)
522 return -RPROC_ENOMEM;
523 memcpy(*shstrtab,
524 (const char *)img_data + shstrtab_offset,
525 shstrtab_size);
526 *load_state = (*load_state & (~ELF_STATE_MASK)) |
527 ELF_STATE_HDRS_COMPLETE;
528 *nlen = 0;
529 return *load_state;
530 }
531 return last_load_state;
532 }
533
elf_load(struct remoteproc * rproc,const void * img_data,size_t offset,size_t len,void ** img_info,int last_load_state,metal_phys_addr_t * da,size_t * noffset,size_t * nlen,unsigned char * padding,size_t * nmemsize)534 int elf_load(struct remoteproc *rproc,
535 const void *img_data, size_t offset, size_t len,
536 void **img_info, int last_load_state,
537 metal_phys_addr_t *da,
538 size_t *noffset, size_t *nlen,
539 unsigned char *padding, size_t *nmemsize)
540 {
541 int *load_state;
542 const void *phdr;
543
544 (void)rproc;
545 metal_assert(da);
546 metal_assert(noffset);
547 metal_assert(nlen);
548 if ((last_load_state & RPROC_LOADER_MASK) == RPROC_LOADER_NOT_READY) {
549 metal_log(METAL_LOG_DEBUG,
550 "needs to load header first\r\n");
551 last_load_state = elf_load_header(img_data, offset, len,
552 img_info, last_load_state,
553 noffset, nlen);
554 if ((last_load_state & RPROC_LOADER_MASK) ==
555 RPROC_LOADER_NOT_READY) {
556 *da = RPROC_LOAD_ANYADDR;
557 return last_load_state;
558 }
559 }
560 metal_assert(img_info && *img_info);
561 load_state = elf_load_state(*img_info);
562 /* For ELF, segment padding value is 0 */
563 if (padding)
564 *padding = 0;
565 if ((*load_state & RPROC_LOADER_READY_TO_LOAD) != 0) {
566 int nsegment;
567 size_t nsegmsize = 0;
568 size_t nsize = 0;
569 int phnums = 0;
570
571 nsegment = *load_state & ELF_NEXT_SEGMENT_MASK;
572 phdr = elf_next_load_segment(*img_info, &nsegment, da,
573 noffset, &nsize, &nsegmsize);
574 if (!phdr) {
575 metal_log(METAL_LOG_DEBUG, "cannot find more segment\r\n");
576 *load_state = (*load_state & (~ELF_NEXT_SEGMENT_MASK)) |
577 (nsegment & ELF_NEXT_SEGMENT_MASK);
578 return *load_state;
579 }
580 *nlen = nsize;
581 *nmemsize = nsegmsize;
582 phnums = elf_phnum(*img_info);
583 metal_log(METAL_LOG_DEBUG, "segment: %d, total segs %d\r\n",
584 nsegment, phnums);
585 if (nsegment == phnums) {
586 *load_state = (*load_state & (~RPROC_LOADER_MASK)) |
587 RPROC_LOADER_POST_DATA_LOAD;
588 }
589 *load_state = (*load_state & (~ELF_NEXT_SEGMENT_MASK)) |
590 (nsegment & ELF_NEXT_SEGMENT_MASK);
591 } else if ((*load_state & RPROC_LOADER_POST_DATA_LOAD) != 0) {
592 if ((*load_state & ELF_STATE_HDRS_COMPLETE) == 0) {
593 last_load_state = elf_load_header(img_data, offset,
594 len, img_info,
595 last_load_state,
596 noffset, nlen);
597 if (last_load_state < 0)
598 return last_load_state;
599 if ((last_load_state & ELF_STATE_HDRS_COMPLETE) != 0) {
600 *load_state = (*load_state &
601 (~RPROC_LOADER_MASK)) |
602 RPROC_LOADER_LOAD_COMPLETE;
603 *nlen = 0;
604 }
605 *da = RPROC_LOAD_ANYADDR;
606 } else {
607 /* TODO: will handle relocate later */
608 *nlen = 0;
609 *load_state = (*load_state &
610 (~RPROC_LOADER_MASK)) |
611 RPROC_LOADER_LOAD_COMPLETE;
612 }
613 }
614 return *load_state;
615 }
616
elf_release(void * img_info)617 void elf_release(void *img_info)
618 {
619 if (!img_info)
620 return;
621 if (elf_is_64(img_info) == 0) {
622 struct elf32_info *elf_info = img_info;
623
624 if (elf_info->phdrs)
625 metal_free_memory(elf_info->phdrs);
626 if (elf_info->shdrs)
627 metal_free_memory(elf_info->shdrs);
628 if (elf_info->shstrtab)
629 metal_free_memory(elf_info->shstrtab);
630 metal_free_memory(img_info);
631
632 } else {
633 struct elf64_info *elf_info = img_info;
634
635 if (elf_info->phdrs)
636 metal_free_memory(elf_info->phdrs);
637 if (elf_info->shdrs)
638 metal_free_memory(elf_info->shdrs);
639 if (elf_info->shstrtab)
640 metal_free_memory(elf_info->shstrtab);
641 metal_free_memory(img_info);
642 }
643 }
644
elf_get_entry(void * elf_info)645 metal_phys_addr_t elf_get_entry(void *elf_info)
646 {
647 if (!elf_info)
648 return METAL_BAD_PHYS;
649
650 if (elf_is_64(elf_info) == 0) {
651 Elf32_Ehdr *elf_ehdr = elf_info;
652 Elf32_Addr e_entry;
653
654 e_entry = elf_ehdr->e_entry;
655 return (metal_phys_addr_t)e_entry;
656 } else {
657 Elf64_Ehdr *elf_ehdr = elf_info;
658 Elf64_Addr e_entry;
659
660 e_entry = elf_ehdr->e_entry;
661 return (metal_phys_addr_t)e_entry;
662 }
663 }
664
elf_locate_rsc_table(void * elf_info,metal_phys_addr_t * da,size_t * offset,size_t * size)665 int elf_locate_rsc_table(void *elf_info, metal_phys_addr_t *da,
666 size_t *offset, size_t *size)
667 {
668 char *sect_name = ".resource_table";
669 void *shdr;
670 int *load_state;
671
672 if (!elf_info)
673 return -RPROC_EINVAL;
674
675 load_state = elf_load_state(elf_info);
676 if ((*load_state & ELF_STATE_HDRS_COMPLETE) == 0)
677 return -RPROC_ERR_LOADER_STATE;
678 shdr = elf_get_section_from_name(elf_info, sect_name);
679 if (!shdr) {
680 metal_assert(size);
681 *size = 0;
682 return 0;
683 }
684 elf_parse_section(elf_info, shdr, NULL, NULL,
685 da, offset, size,
686 NULL, NULL, NULL, NULL);
687 return 0;
688 }
689
elf_get_load_state(void * img_info)690 int elf_get_load_state(void *img_info)
691 {
692 int *load_state;
693
694 if (!img_info)
695 return -RPROC_EINVAL;
696 load_state = elf_load_state(img_info);
697 return *load_state;
698 }
699
700 const struct loader_ops elf_ops = {
701 .load_header = elf_load_header,
702 .load_data = elf_load,
703 .locate_rsc_table = elf_locate_rsc_table,
704 .release = elf_release,
705 .get_entry = elf_get_entry,
706 .get_load_state = elf_get_load_state,
707 };
708