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