Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / SLOF / lib / libelf / elf32.c
1 /******************************************************************************
2  * Copyright (c) 2004, 2011 IBM Corporation
3  * All rights reserved.
4  * This program and the accompanying materials
5  * are made available under the terms of the BSD License
6  * which accompanies this distribution, and is available at
7  * http://www.opensource.org/licenses/bsd-license.php
8  *
9  * Contributors:
10  *     IBM Corporation - initial implementation
11  *****************************************************************************/
12
13 /*
14  * 32-bit ELF loader
15  */
16 #include <stdio.h> 
17 #include <string.h>
18 #include <libelf.h>
19 #include <byteorder.h>
20
21 struct ehdr32 {
22         uint32_t ei_ident;
23         uint8_t ei_class;
24         uint8_t ei_data;
25         uint8_t ei_version;
26         uint8_t ei_pad[9];
27         uint16_t e_type;
28         uint16_t e_machine;
29         uint32_t e_version;
30         uint32_t e_entry;
31         uint32_t e_phoff;
32         uint32_t e_shoff;
33         uint32_t e_flags;
34         uint16_t e_ehsize;
35         uint16_t e_phentsize;
36         uint16_t e_phnum;
37         uint16_t e_shentsize;
38         uint16_t e_shnum;
39         uint16_t e_shstrndx;
40 };
41
42 struct phdr32 {
43         uint32_t p_type;
44         uint32_t p_offset;
45         uint32_t p_vaddr;
46         uint32_t p_paddr;
47         uint32_t p_filesz;
48         uint32_t p_memsz;
49         uint32_t p_flags;
50         uint32_t p_align;
51 };
52
53
54 static struct phdr32*
55 get_phdr32(void *file_addr)
56 {
57         return (struct phdr32 *) (((unsigned char *)file_addr)
58                 + ((struct ehdr32 *)file_addr)->e_phoff);
59 }
60
61 static void
62 load_segment(void *file_addr, struct phdr32 *phdr, signed long offset,
63              int (*pre_load)(void*, long),
64              void (*post_load)(void*, long))
65 {
66         unsigned long src = phdr->p_offset + (unsigned long) file_addr;
67         unsigned long destaddr;
68
69         destaddr = (unsigned long)phdr->p_paddr;
70         destaddr = destaddr + offset;
71
72         /* check if we're allowed to copy */
73         if (pre_load != NULL) {
74                 if (pre_load((void*)destaddr, phdr->p_memsz) != 0)
75                         return;
76         }
77
78         /* copy into storage */
79         memmove((void *)destaddr, (void *)src, phdr->p_filesz);
80
81         /* clear bss */
82         memset((void *)(destaddr + phdr->p_filesz), 0,
83                phdr->p_memsz - phdr->p_filesz);
84
85         if (phdr->p_memsz && post_load) {
86                 post_load((void*)destaddr, phdr->p_memsz);
87         }
88 }
89
90 unsigned int
91 elf_load_segments32(void *file_addr, signed long offset,
92                     int (*pre_load)(void*, long),
93                     void (*post_load)(void*, long))
94 {
95         struct ehdr32 *ehdr = (struct ehdr32 *) file_addr;
96         /* Calculate program header address */
97         struct phdr32 *phdr = get_phdr32(file_addr);
98         int i;
99
100         /* loop e_phnum times */
101         for (i = 0; i <= ehdr->e_phnum; i++) {
102                 /* PT_LOAD ? */
103                 if (phdr->p_type == 1) {
104                         if (phdr->p_paddr != phdr->p_vaddr) {
105                                 printf("ELF32: VirtAddr(%lx) != PhysAddr(%lx) not supported, aborting\n",
106                                         (long)phdr->p_vaddr, (long)phdr->p_paddr);
107                                 return 0;
108                         }
109
110                         /* copy segment */
111                         load_segment(file_addr, phdr, offset, pre_load,
112                                      post_load);
113                 }
114                 /* step to next header */
115                 phdr = (struct phdr32 *)(((uint8_t *)phdr) + ehdr->e_phentsize);
116         }
117
118         /* Entry point is always a virtual address, so translate it
119          * to physical before returning it */
120         return ehdr->e_entry;
121 }
122
123 /**
124  * Return the base address for loading (i.e. the address of the first PT_LOAD
125  * segment)
126  * @param  file_addr    pointer to the ELF file in memory
127  * @return              the base address
128  */
129 long
130 elf_get_base_addr32(void *file_addr)
131 {
132         struct ehdr32 *ehdr = (struct ehdr32 *) file_addr;
133         struct phdr32 *phdr = get_phdr32(file_addr);
134         int i;
135
136         /* loop e_phnum times */
137         for (i = 0; i <= ehdr->e_phnum; i++) {
138                 /* PT_LOAD ? */
139                 if (phdr->p_type == 1) {
140                         return phdr->p_paddr;
141                 }
142                 /* step to next header */
143                 phdr = (struct phdr32 *)(((uint8_t *)phdr) + ehdr->e_phentsize);
144         }
145
146         return 0;
147 }
148
149 uint32_t elf_get_eflags_32(void *file_addr)
150 {
151         struct ehdr32 *ehdr = (struct ehdr32 *) file_addr;
152
153         return ehdr->e_flags;
154 }
155
156 void
157 elf_byteswap_header32(void *file_addr)
158 {
159         struct ehdr32 *ehdr = (struct ehdr32 *) file_addr;
160         struct phdr32 *phdr;
161         int i;
162
163         bswap_16p(&ehdr->e_type);
164         bswap_16p(&ehdr->e_machine);
165         bswap_32p(&ehdr->e_version);
166         bswap_32p(&ehdr->e_entry);
167         bswap_32p(&ehdr->e_phoff);
168         bswap_32p(&ehdr->e_shoff);
169         bswap_32p(&ehdr->e_flags);
170         bswap_16p(&ehdr->e_ehsize);
171         bswap_16p(&ehdr->e_phentsize);
172         bswap_16p(&ehdr->e_phnum);
173         bswap_16p(&ehdr->e_shentsize);
174         bswap_16p(&ehdr->e_shnum);
175         bswap_16p(&ehdr->e_shstrndx);
176
177         phdr = get_phdr32(file_addr);
178
179         /* loop e_phnum times */
180         for (i = 0; i <= ehdr->e_phnum; i++) {
181                 bswap_32p(&phdr->p_type);
182                 bswap_32p(&phdr->p_offset);
183                 bswap_32p(&phdr->p_vaddr);
184                 bswap_32p(&phdr->p_paddr);
185                 bswap_32p(&phdr->p_filesz);
186                 bswap_32p(&phdr->p_memsz);
187                 bswap_32p(&phdr->p_flags);
188                 bswap_32p(&phdr->p_align);
189
190                 /* step to next header */
191                 phdr = (struct phdr32 *)(((uint8_t *)phdr) + ehdr->e_phentsize);
192         }
193 }