ia64/xen-unstable

view tools/libxc/xc_load_elf.c @ 10123:d9f63f9361c4

[LOADER] Another change to the elf_paddr_offset/virt_base logic.
This avoids using zero to indicate 'undefined'. Instead we use
an explicit boolean to indicate whether suitable defaults should
be used. As well as making the logic clearer (I believe) it also
avoids problems if anyone ever explicitly specifies virt_base
(and also elf_paddr_offset) as zero.

Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Sun May 21 18:55:14 2006 +0100 (2006-05-21)
parents 4dcb93547710
children 14717dedba02
line source
1 /******************************************************************************
2 * xc_elf_load.c
3 */
5 #include "xg_private.h"
7 #if defined(__i386__)
8 #define ELFSIZE 32
9 #endif
10 #if defined(__x86_64__) || defined(__ia64__)
11 #define ELFSIZE 64
12 #endif
14 #include "xc_elf.h"
15 #include <stdlib.h>
17 #define round_pgup(_p) (((_p)+(PAGE_SIZE-1))&PAGE_MASK)
18 #define round_pgdown(_p) ((_p)&PAGE_MASK)
20 static int
21 parseelfimage(
22 const char *image, unsigned long image_size,
23 struct domain_setup_info *dsi);
24 static int
25 loadelfimage(
26 const char *image, unsigned long image_size, int xch, uint32_t dom,
27 unsigned long *parray, struct domain_setup_info *dsi);
28 static int
29 loadelfsymtab(
30 const char *image, int xch, uint32_t dom, unsigned long *parray,
31 struct domain_setup_info *dsi);
33 int probe_elf(const char *image,
34 unsigned long image_size,
35 struct load_funcs *load_funcs)
36 {
37 Elf_Ehdr *ehdr = (Elf_Ehdr *)image;
39 if ( !IS_ELF(*ehdr) )
40 return -EINVAL;
42 load_funcs->parseimage = parseelfimage;
43 load_funcs->loadimage = loadelfimage;
45 return 0;
46 }
48 static inline int is_loadable_phdr(Elf_Phdr *phdr)
49 {
50 return ((phdr->p_type == PT_LOAD) &&
51 ((phdr->p_flags & (PF_W|PF_X)) != 0));
52 }
54 static int parseelfimage(const char *image,
55 unsigned long elfsize,
56 struct domain_setup_info *dsi)
57 {
58 Elf_Ehdr *ehdr = (Elf_Ehdr *)image;
59 Elf_Phdr *phdr;
60 Elf_Shdr *shdr;
61 unsigned long kernstart = ~0UL, kernend=0UL, vaddr, virt_base, elf_pa_off;
62 const char *shstrtab;
63 char *guestinfo=NULL, *p;
64 int h, virt_base_defined, elf_pa_off_defined;
66 if ( !IS_ELF(*ehdr) )
67 {
68 ERROR("Kernel image does not have an ELF header.");
69 return -EINVAL;
70 }
72 if (
73 #if defined(__i386__)
74 (ehdr->e_ident[EI_CLASS] != ELFCLASS32) ||
75 (ehdr->e_machine != EM_386) ||
76 #elif defined(__x86_64__)
77 (ehdr->e_ident[EI_CLASS] != ELFCLASS64) ||
78 (ehdr->e_machine != EM_X86_64) ||
79 #endif
80 (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) ||
81 (ehdr->e_type != ET_EXEC) )
82 {
83 ERROR("Kernel not a Xen-compatible Elf image.");
84 return -EINVAL;
85 }
87 if ( (ehdr->e_phoff + (ehdr->e_phnum * ehdr->e_phentsize)) > elfsize )
88 {
89 ERROR("ELF program headers extend beyond end of image.");
90 return -EINVAL;
91 }
93 if ( (ehdr->e_shoff + (ehdr->e_shnum * ehdr->e_shentsize)) > elfsize )
94 {
95 ERROR("ELF section headers extend beyond end of image.");
96 return -EINVAL;
97 }
99 /* Find the section-header strings table. */
100 if ( ehdr->e_shstrndx == SHN_UNDEF )
101 {
102 ERROR("ELF image has no section-header strings table (shstrtab).");
103 return -EINVAL;
104 }
105 shdr = (Elf_Shdr *)(image + ehdr->e_shoff +
106 (ehdr->e_shstrndx*ehdr->e_shentsize));
107 shstrtab = image + shdr->sh_offset;
109 /* Find the special '__xen_guest' section and check its contents. */
110 for ( h = 0; h < ehdr->e_shnum; h++ )
111 {
112 shdr = (Elf_Shdr *)(image + ehdr->e_shoff + (h*ehdr->e_shentsize));
113 if ( strcmp(&shstrtab[shdr->sh_name], "__xen_guest") != 0 )
114 continue;
116 guestinfo = (char *)image + shdr->sh_offset;
118 if ( (strstr(guestinfo, "LOADER=generic") == NULL) &&
119 (strstr(guestinfo, "GUEST_OS=linux") == NULL) )
120 {
121 ERROR("Will only load images built for the generic loader "
122 "or Linux images");
123 ERROR("Actually saw: '%s'", guestinfo);
124 return -EINVAL;
125 }
127 if ( (strstr(guestinfo, "XEN_VER=xen-3.0") == NULL) )
128 {
129 ERROR("Will only load images built for Xen v3.0");
130 ERROR("Actually saw: '%s'", guestinfo);
131 return -EINVAL;
132 }
133 if ( (strstr(guestinfo, "PAE=yes") != NULL) )
134 dsi->pae_kernel = 1;
136 break;
137 }
139 if ( guestinfo == NULL )
140 {
141 #ifdef __ia64__
142 guestinfo = "";
143 #else
144 ERROR("Not a Xen-ELF image: '__xen_guest' section not found.");
145 return -EINVAL;
146 #endif
147 }
149 dsi->xen_guest_string = guestinfo;
151 /* Initial guess for virt_base is 0 if it is not explicitly defined. */
152 p = strstr(guestinfo, "VIRT_BASE=");
153 virt_base_defined = (p != NULL);
154 virt_base = virt_base_defined ? strtoul(p+10, &p, 0) : 0;
156 /* Initial guess for elf_pa_off is virt_base if not explicitly defined. */
157 p = strstr(guestinfo, "ELF_PADDR_OFFSET=");
158 elf_pa_off_defined = (p != NULL);
159 elf_pa_off = elf_pa_off_defined ? strtoul(p+17, &p, 0) : virt_base;
161 for ( h = 0; h < ehdr->e_phnum; h++ )
162 {
163 phdr = (Elf_Phdr *)(image + ehdr->e_phoff + (h*ehdr->e_phentsize));
164 if ( !is_loadable_phdr(phdr) )
165 continue;
166 vaddr = phdr->p_paddr - elf_pa_off + virt_base;
167 if ( vaddr < kernstart )
168 kernstart = vaddr;
169 if ( (vaddr + phdr->p_memsz) > kernend )
170 kernend = vaddr + phdr->p_memsz;
171 }
173 /*
174 * Legacy compatibility and images with no __xen_guest section: assume
175 * header addresses are virtual addresses, and that guest memory should be
176 * mapped starting at kernel load address.
177 */
178 dsi->v_start = virt_base_defined ? virt_base : kernstart;
179 dsi->elf_paddr_offset = elf_pa_off_defined ? elf_pa_off : dsi->v_start;
181 dsi->v_kernentry = ehdr->e_entry;
182 if ( (p = strstr(guestinfo, "VIRT_ENTRY=")) != NULL )
183 dsi->v_kernentry = strtoul(p+11, &p, 0);
185 if ( (kernstart > kernend) ||
186 (dsi->v_kernentry < kernstart) ||
187 (dsi->v_kernentry > kernend) )
188 {
189 ERROR("Malformed ELF image.");
190 return -EINVAL;
191 }
193 if ( (p = strstr(guestinfo, "BSD_SYMTAB")) != NULL )
194 dsi->load_symtab = 1;
196 dsi->v_kernstart = kernstart;
197 dsi->v_kernend = kernend;
198 dsi->v_end = dsi->v_kernend;
200 loadelfsymtab(image, 0, 0, NULL, dsi);
202 return 0;
203 }
205 static int
206 loadelfimage(
207 const char *image, unsigned long elfsize, int xch, uint32_t dom,
208 unsigned long *parray, struct domain_setup_info *dsi)
209 {
210 Elf_Ehdr *ehdr = (Elf_Ehdr *)image;
211 Elf_Phdr *phdr;
212 int h;
214 char *va;
215 unsigned long pa, done, chunksz;
217 for ( h = 0; h < ehdr->e_phnum; h++ )
218 {
219 phdr = (Elf_Phdr *)(image + ehdr->e_phoff + (h*ehdr->e_phentsize));
220 if ( !is_loadable_phdr(phdr) )
221 continue;
223 for ( done = 0; done < phdr->p_filesz; done += chunksz )
224 {
225 pa = (phdr->p_paddr + done) - dsi->elf_paddr_offset;
226 va = xc_map_foreign_range(
227 xch, dom, PAGE_SIZE, PROT_WRITE, parray[pa>>PAGE_SHIFT]);
228 if ( va == NULL )
229 return -1;
230 chunksz = phdr->p_filesz - done;
231 if ( chunksz > (PAGE_SIZE - (pa & (PAGE_SIZE-1))) )
232 chunksz = PAGE_SIZE - (pa & (PAGE_SIZE-1));
233 memcpy(va + (pa & (PAGE_SIZE-1)),
234 image + phdr->p_offset + done, chunksz);
235 munmap(va, PAGE_SIZE);
236 }
238 for ( ; done < phdr->p_memsz; done += chunksz )
239 {
240 pa = (phdr->p_paddr + done) - dsi->elf_paddr_offset;
241 va = xc_map_foreign_range(
242 xch, dom, PAGE_SIZE, PROT_WRITE, parray[pa>>PAGE_SHIFT]);
243 if ( va == NULL )
244 return -1;
245 chunksz = phdr->p_memsz - done;
246 if ( chunksz > (PAGE_SIZE - (pa & (PAGE_SIZE-1))) )
247 chunksz = PAGE_SIZE - (pa & (PAGE_SIZE-1));
248 memset(va + (pa & (PAGE_SIZE-1)), 0, chunksz);
249 munmap(va, PAGE_SIZE);
250 }
251 }
253 loadelfsymtab(image, xch, dom, parray, dsi);
255 return 0;
256 }
258 #define ELFROUND (ELFSIZE / 8)
260 static int
261 loadelfsymtab(
262 const char *image, int xch, uint32_t dom, unsigned long *parray,
263 struct domain_setup_info *dsi)
264 {
265 Elf_Ehdr *ehdr = (Elf_Ehdr *)image, *sym_ehdr;
266 Elf_Shdr *shdr;
267 unsigned long maxva, symva;
268 char *p;
269 int h, i;
271 if ( !dsi->load_symtab )
272 return 0;
274 p = malloc(sizeof(int) + sizeof(Elf_Ehdr) +
275 ehdr->e_shnum * sizeof(Elf_Shdr));
276 if (p == NULL)
277 return 0;
279 maxva = (dsi->v_kernend + ELFROUND - 1) & ~(ELFROUND - 1);
280 symva = maxva;
281 maxva += sizeof(int);
282 dsi->symtab_addr = maxva;
283 dsi->symtab_len = 0;
284 maxva += sizeof(Elf_Ehdr) + ehdr->e_shnum * sizeof(Elf_Shdr);
285 maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1);
287 shdr = (Elf_Shdr *)(p + sizeof(int) + sizeof(Elf_Ehdr));
288 memcpy(shdr, image + ehdr->e_shoff, ehdr->e_shnum * sizeof(Elf_Shdr));
290 for ( h = 0; h < ehdr->e_shnum; h++ )
291 {
292 if ( shdr[h].sh_type == SHT_STRTAB )
293 {
294 /* Look for a strtab @i linked to symtab @h. */
295 for ( i = 0; i < ehdr->e_shnum; i++ )
296 if ( (shdr[i].sh_type == SHT_SYMTAB) &&
297 (shdr[i].sh_link == h) )
298 break;
299 /* Skip symtab @h if we found no corresponding strtab @i. */
300 if ( i == ehdr->e_shnum )
301 {
302 shdr[h].sh_offset = 0;
303 continue;
304 }
305 }
307 if ( (shdr[h].sh_type == SHT_STRTAB) ||
308 (shdr[h].sh_type == SHT_SYMTAB) )
309 {
310 if ( parray != NULL )
311 xc_map_memcpy(maxva, image + shdr[h].sh_offset,
312 shdr[h].sh_size,
313 xch, dom, parray, dsi->v_start);
315 /* Mangled to be based on ELF header location. */
316 shdr[h].sh_offset = maxva - dsi->symtab_addr;
318 dsi->symtab_len += shdr[h].sh_size;
319 maxva += shdr[h].sh_size;
320 maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1);
321 }
323 shdr[h].sh_name = 0; /* Name is NULL. */
324 }
326 if ( dsi->symtab_len == 0 )
327 {
328 dsi->symtab_addr = 0;
329 goto out;
330 }
332 if ( parray != NULL )
333 {
334 *(int *)p = maxva - dsi->symtab_addr;
335 sym_ehdr = (Elf_Ehdr *)(p + sizeof(int));
336 memcpy(sym_ehdr, ehdr, sizeof(Elf_Ehdr));
337 sym_ehdr->e_phoff = 0;
338 sym_ehdr->e_shoff = sizeof(Elf_Ehdr);
339 sym_ehdr->e_phentsize = 0;
340 sym_ehdr->e_phnum = 0;
341 sym_ehdr->e_shstrndx = SHN_UNDEF;
343 /* Copy total length, crafted ELF header and section header table */
344 xc_map_memcpy(symva, p, sizeof(int) + sizeof(Elf_Ehdr) +
345 ehdr->e_shnum * sizeof(Elf_Shdr), xch, dom, parray,
346 dsi->v_start);
347 }
349 dsi->symtab_len = maxva - dsi->symtab_addr;
350 dsi->v_end = round_pgup(maxva);
352 out:
353 free(p);
355 return 0;
356 }
358 /*
359 * Local variables:
360 * mode: C
361 * c-set-style: "BSD"
362 * c-basic-offset: 4
363 * tab-width: 4
364 * indent-tabs-mode: nil
365 * End:
366 */