ia64/xen-unstable

view xen/common/elf.c @ 11128:f2f584093379

[POWERPC] Update .hgignore
Signed-off-by: Hollis Blanchard <hollisb@us.ibm.com>
author kfraser@localhost.localdomain
date Tue Aug 15 10:38:59 2006 +0100 (2006-08-15)
parents cda7b6017a76
children 03fd2accb4d9
line source
1 /******************************************************************************
2 * elf.c
3 *
4 * Generic Elf-loading routines.
5 */
7 #include <xen/config.h>
8 #include <xen/init.h>
9 #include <xen/lib.h>
10 #include <xen/mm.h>
11 #include <xen/elf.h>
12 #include <xen/sched.h>
14 static void loadelfsymtab(struct domain_setup_info *dsi, int doload);
15 static inline int is_loadable_phdr(Elf_Phdr *phdr)
16 {
17 return ((phdr->p_type == PT_LOAD) &&
18 ((phdr->p_flags & (PF_W|PF_X)) != 0));
19 }
21 int parseelfimage(struct domain_setup_info *dsi)
22 {
23 Elf_Ehdr *ehdr = (Elf_Ehdr *)dsi->image_addr;
24 Elf_Phdr *phdr;
25 Elf_Shdr *shdr;
26 Elf_Addr kernstart = ~0, kernend = 0, vaddr, virt_base, elf_pa_off;
27 char *shstrtab, *guestinfo=NULL, *p;
28 char *elfbase = (char *)dsi->image_addr;
29 int h, virt_base_defined, elf_pa_off_defined;
31 if ( !elf_sanity_check(ehdr) )
32 return -EINVAL;
34 if ( (ehdr->e_phoff + (ehdr->e_phnum*ehdr->e_phentsize)) > dsi->image_len )
35 {
36 printk("ELF program headers extend beyond end of image.\n");
37 return -EINVAL;
38 }
40 if ( (ehdr->e_shoff + (ehdr->e_shnum*ehdr->e_shentsize)) > dsi->image_len )
41 {
42 printk("ELF section headers extend beyond end of image.\n");
43 return -EINVAL;
44 }
46 /* Find the section-header strings table. */
47 if ( ehdr->e_shstrndx == SHN_UNDEF )
48 {
49 printk("ELF image has no section-header strings table (shstrtab).\n");
50 return -EINVAL;
51 }
52 shdr = (Elf_Shdr *)(elfbase + ehdr->e_shoff +
53 (ehdr->e_shstrndx*ehdr->e_shentsize));
54 shstrtab = elfbase + shdr->sh_offset;
56 /* Find the special '__xen_guest' section and check its contents. */
57 for ( h = 0; h < ehdr->e_shnum; h++ )
58 {
59 shdr = (Elf_Shdr *)(elfbase + ehdr->e_shoff + (h*ehdr->e_shentsize));
60 if ( strcmp(&shstrtab[shdr->sh_name], "__xen_guest") != 0 )
61 continue;
63 guestinfo = elfbase + shdr->sh_offset;
65 if ( (strstr(guestinfo, "LOADER=generic") == NULL) &&
66 (strstr(guestinfo, "GUEST_OS=linux") == NULL) )
67 {
68 printk("ERROR: Xen will only load images built for the generic "
69 "loader or Linux images\n");
70 return -EINVAL;
71 }
73 if ( (strstr(guestinfo, "XEN_VER=xen-3.0") == NULL) )
74 {
75 printk("ERROR: Xen will only load images built for Xen v3.0\n");
76 return -EINVAL;
77 }
79 break;
80 }
82 dsi->xen_section_string = guestinfo;
84 if ( guestinfo == NULL )
85 guestinfo = "";
87 /* Initial guess for virt_base is 0 if it is not explicitly defined. */
88 p = strstr(guestinfo, "VIRT_BASE=");
89 virt_base_defined = (p != NULL);
90 virt_base = virt_base_defined ? simple_strtoul(p+10, &p, 0) : 0;
92 /* Initial guess for elf_pa_off is virt_base if not explicitly defined. */
93 p = strstr(guestinfo, "ELF_PADDR_OFFSET=");
94 elf_pa_off_defined = (p != NULL);
95 elf_pa_off = elf_pa_off_defined ? simple_strtoul(p+17, &p, 0) : virt_base;
97 if ( elf_pa_off_defined && !virt_base_defined )
98 {
99 printk("ERROR: Neither ELF_PADDR_OFFSET nor VIRT_BASE found in"
100 " __xen_guest section.\n");
101 return -EINVAL;
102 }
104 for ( h = 0; h < ehdr->e_phnum; h++ )
105 {
106 phdr = (Elf_Phdr *)(elfbase + ehdr->e_phoff + (h*ehdr->e_phentsize));
107 if ( !is_loadable_phdr(phdr) )
108 continue;
109 vaddr = phdr->p_paddr - elf_pa_off + virt_base;
110 if ( (vaddr + phdr->p_memsz) < vaddr )
111 {
112 printk("ERROR: ELF program header %d is too large.\n", h);
113 return -EINVAL;
114 }
116 if ( vaddr < kernstart )
117 kernstart = vaddr;
118 if ( (vaddr + phdr->p_memsz) > kernend )
119 kernend = vaddr + phdr->p_memsz;
120 }
122 /*
123 * Legacy compatibility and images with no __xen_guest section: assume
124 * header addresses are virtual addresses, and that guest memory should be
125 * mapped starting at kernel load address.
126 */
127 dsi->v_start = virt_base_defined ? virt_base : kernstart;
128 dsi->elf_paddr_offset = elf_pa_off_defined ? elf_pa_off : dsi->v_start;
130 dsi->v_kernentry = ehdr->e_entry;
131 if ( (p = strstr(guestinfo, "VIRT_ENTRY=")) != NULL )
132 dsi->v_kernentry = simple_strtoul(p+11, &p, 0);
134 if ( (kernstart > kernend) ||
135 (dsi->v_kernentry < kernstart) ||
136 (dsi->v_kernentry > kernend) ||
137 (dsi->v_start > kernstart) )
138 {
139 printk("ERROR: ELF start or entries are out of bounds.\n");
140 return -EINVAL;
141 }
143 if ( (p = strstr(guestinfo, "BSD_SYMTAB")) != NULL )
144 dsi->load_symtab = 1;
146 dsi->v_kernstart = kernstart;
147 dsi->v_kernend = kernend;
148 dsi->v_end = dsi->v_kernend;
150 loadelfsymtab(dsi, 0);
152 return 0;
153 }
155 int loadelfimage(struct domain_setup_info *dsi)
156 {
157 char *elfbase = (char *)dsi->image_addr;
158 Elf_Ehdr *ehdr = (Elf_Ehdr *)dsi->image_addr;
159 Elf_Phdr *phdr;
160 unsigned long vaddr;
161 int h;
163 for ( h = 0; h < ehdr->e_phnum; h++ )
164 {
165 phdr = (Elf_Phdr *)(elfbase + ehdr->e_phoff + (h*ehdr->e_phentsize));
166 if ( !is_loadable_phdr(phdr) )
167 continue;
168 vaddr = phdr->p_paddr - dsi->elf_paddr_offset + dsi->v_start;
169 if ( phdr->p_filesz != 0 )
170 memcpy((char *)vaddr, elfbase + phdr->p_offset, phdr->p_filesz);
171 if ( phdr->p_memsz > phdr->p_filesz )
172 memset((char *)vaddr + phdr->p_filesz, 0,
173 phdr->p_memsz - phdr->p_filesz);
174 }
176 loadelfsymtab(dsi, 1);
178 return 0;
179 }
181 #define ELFROUND (ELFSIZE / 8)
183 static void loadelfsymtab(struct domain_setup_info *dsi, int doload)
184 {
185 Elf_Ehdr *ehdr = (Elf_Ehdr *)dsi->image_addr, *sym_ehdr;
186 Elf_Shdr *shdr;
187 unsigned long maxva, symva;
188 char *p, *elfbase = (char *)dsi->image_addr;
189 int h, i;
191 if ( !dsi->load_symtab )
192 return;
194 maxva = (dsi->v_kernend + ELFROUND - 1) & ~(ELFROUND - 1);
195 symva = maxva;
196 maxva += sizeof(int);
197 dsi->symtab_addr = maxva;
198 dsi->symtab_len = 0;
199 maxva += sizeof(Elf_Ehdr) + ehdr->e_shnum * sizeof(Elf_Shdr);
200 maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1);
201 if ( doload )
202 {
203 p = (void *)symva;
204 shdr = (Elf_Shdr *)(p + sizeof(int) + sizeof(Elf_Ehdr));
205 memcpy(shdr, elfbase + ehdr->e_shoff, ehdr->e_shnum*sizeof(Elf_Shdr));
206 }
207 else
208 {
209 p = NULL;
210 shdr = (Elf_Shdr *)(elfbase + ehdr->e_shoff);
211 }
213 for ( h = 0; h < ehdr->e_shnum; h++ )
214 {
215 if ( shdr[h].sh_type == SHT_STRTAB )
216 {
217 /* Look for a strtab @i linked to symtab @h. */
218 for ( i = 0; i < ehdr->e_shnum; i++ )
219 if ( (shdr[i].sh_type == SHT_SYMTAB) &&
220 (shdr[i].sh_link == h) )
221 break;
222 /* Skip symtab @h if we found no corresponding strtab @i. */
223 if ( i == ehdr->e_shnum )
224 {
225 if (doload) {
226 shdr[h].sh_offset = 0;
227 }
228 continue;
229 }
230 }
232 if ( (shdr[h].sh_type == SHT_STRTAB) ||
233 (shdr[h].sh_type == SHT_SYMTAB) )
234 {
235 if (doload) {
236 memcpy((void *)maxva, elfbase + shdr[h].sh_offset,
237 shdr[h].sh_size);
239 /* Mangled to be based on ELF header location. */
240 shdr[h].sh_offset = maxva - dsi->symtab_addr;
242 }
243 dsi->symtab_len += shdr[h].sh_size;
244 maxva += shdr[h].sh_size;
245 maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1);
246 }
248 if ( doload )
249 shdr[h].sh_name = 0; /* Name is NULL. */
250 }
252 if ( dsi->symtab_len == 0 )
253 {
254 dsi->symtab_addr = 0;
255 return;
256 }
258 if ( doload )
259 {
260 *(int *)p = maxva - dsi->symtab_addr;
261 sym_ehdr = (Elf_Ehdr *)(p + sizeof(int));
262 memcpy(sym_ehdr, ehdr, sizeof(Elf_Ehdr));
263 sym_ehdr->e_phoff = 0;
264 sym_ehdr->e_shoff = sizeof(Elf_Ehdr);
265 sym_ehdr->e_phentsize = 0;
266 sym_ehdr->e_phnum = 0;
267 sym_ehdr->e_shstrndx = SHN_UNDEF;
268 }
270 dsi->symtab_len = maxva - dsi->symtab_addr;
271 dsi->v_end = maxva;
272 }
274 /*
275 * Local variables:
276 * mode: C
277 * c-set-style: "BSD"
278 * c-basic-offset: 4
279 * tab-width: 4
280 * indent-tabs-mode: nil
281 * End:
282 */