ia64/xen-unstable

view tools/libxc/xc_load_elf.c @ 7238:971e7c7411b3

Raise an exception if an error appears on the pipes to our children, and make
sure that the child's pipes are closed even under that exception. Move the
handling of POLLHUP to the end of the loop, so that we guarantee to read any
remaining data from the child if POLLHUP and POLLIN appear at the same time.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author emellor@ewan
date Thu Oct 06 10:13:11 2005 +0100 (2005-10-06)
parents 06d84bf87159
children b3a255e88810
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 char *image, unsigned long image_size, struct domain_setup_info *dsi);
23 static int
24 loadelfimage(
25 char *image, unsigned long image_size, int xch, u32 dom,
26 unsigned long *parray, struct domain_setup_info *dsi);
27 static int
28 loadelfsymtab(
29 char *image, int xch, u32 dom, unsigned long *parray,
30 struct domain_setup_info *dsi);
32 int probe_elf(char *image,
33 unsigned long image_size,
34 struct load_funcs *load_funcs)
35 {
36 Elf_Ehdr *ehdr = (Elf_Ehdr *)image;
38 if ( !IS_ELF(*ehdr) )
39 {
40 return -EINVAL;
41 }
43 load_funcs->parseimage = parseelfimage;
44 load_funcs->loadimage = loadelfimage;
46 return 0;
47 }
49 static inline int is_loadable_phdr(Elf_Phdr *phdr)
50 {
51 return ((phdr->p_type == PT_LOAD) &&
52 ((phdr->p_flags & (PF_W|PF_X)) != 0));
53 }
55 static int parseelfimage(char *image,
56 unsigned long elfsize,
57 struct domain_setup_info *dsi)
58 {
59 Elf_Ehdr *ehdr = (Elf_Ehdr *)image;
60 Elf_Phdr *phdr;
61 Elf_Shdr *shdr;
62 unsigned long kernstart = ~0UL, kernend=0UL;
63 char *shstrtab, *guestinfo=NULL, *p;
64 int h;
66 if ( !IS_ELF(*ehdr) )
67 {
68 ERROR("Kernel image does not have an ELF header.");
69 return -EINVAL;
70 }
72 if ( (ehdr->e_phoff + (ehdr->e_phnum * ehdr->e_phentsize)) > elfsize )
73 {
74 ERROR("ELF program headers extend beyond end of image.");
75 return -EINVAL;
76 }
78 if ( (ehdr->e_shoff + (ehdr->e_shnum * ehdr->e_shentsize)) > elfsize )
79 {
80 ERROR("ELF section headers extend beyond end of image.");
81 return -EINVAL;
82 }
84 /* Find the section-header strings table. */
85 if ( ehdr->e_shstrndx == SHN_UNDEF )
86 {
87 ERROR("ELF image has no section-header strings table (shstrtab).");
88 return -EINVAL;
89 }
90 shdr = (Elf_Shdr *)(image + ehdr->e_shoff +
91 (ehdr->e_shstrndx*ehdr->e_shentsize));
92 shstrtab = image + shdr->sh_offset;
94 /* Find the special '__xen_guest' section and check its contents. */
95 for ( h = 0; h < ehdr->e_shnum; h++ )
96 {
97 shdr = (Elf_Shdr *)(image + ehdr->e_shoff + (h*ehdr->e_shentsize));
98 if ( strcmp(&shstrtab[shdr->sh_name], "__xen_guest") != 0 )
99 continue;
101 guestinfo = image + shdr->sh_offset;
103 if ( (strstr(guestinfo, "LOADER=generic") == NULL) &&
104 (strstr(guestinfo, "GUEST_OS=linux") == NULL) )
105 {
106 ERROR("Will only load images built for the generic loader "
107 "or Linux images");
108 ERROR("Actually saw: '%s'", guestinfo);
109 return -EINVAL;
110 }
112 if ( (strstr(guestinfo, "XEN_VER=3.0") == NULL) )
113 {
114 ERROR("Will only load images built for Xen v3.0");
115 ERROR("Actually saw: '%s'", guestinfo);
116 return -EINVAL;
117 }
118 if ( (strstr(guestinfo, "PAE=yes") != NULL) )
119 dsi->pae_kernel = 1;
121 break;
122 }
123 if ( guestinfo == NULL )
124 {
125 #ifdef __ia64__
126 guestinfo = "";
127 #else
128 ERROR("Not a Xen-ELF image: '__xen_guest' section not found.");
129 return -EINVAL;
130 #endif
131 }
133 for ( h = 0; h < ehdr->e_phnum; h++ )
134 {
135 phdr = (Elf_Phdr *)(image + ehdr->e_phoff + (h*ehdr->e_phentsize));
136 if ( !is_loadable_phdr(phdr) )
137 continue;
138 if ( phdr->p_paddr < kernstart )
139 kernstart = phdr->p_paddr;
140 if ( (phdr->p_paddr + phdr->p_memsz) > kernend )
141 kernend = phdr->p_paddr + phdr->p_memsz;
142 }
144 if ( (kernstart > kernend) ||
145 (ehdr->e_entry < kernstart) ||
146 (ehdr->e_entry > kernend) )
147 {
148 ERROR("Malformed ELF image.");
149 return -EINVAL;
150 }
152 dsi->v_start = kernstart;
153 if ( (p = strstr(guestinfo, "VIRT_BASE=")) != NULL )
154 dsi->v_start = strtoul(p+10, &p, 0);
156 if ( (p = strstr(guestinfo, "BSD_SYMTAB")) != NULL )
157 dsi->load_symtab = 1;
159 dsi->v_kernstart = kernstart;
160 dsi->v_kernend = kernend;
161 dsi->v_kernentry = ehdr->e_entry;
162 dsi->v_end = dsi->v_kernend;
164 loadelfsymtab(image, 0, 0, NULL, dsi);
166 return 0;
167 }
169 static int
170 loadelfimage(
171 char *image, unsigned long elfsize, int xch, u32 dom,
172 unsigned long *parray, struct domain_setup_info *dsi)
173 {
174 Elf_Ehdr *ehdr = (Elf_Ehdr *)image;
175 Elf_Phdr *phdr;
176 int h;
178 char *va;
179 unsigned long pa, done, chunksz;
181 for ( h = 0; h < ehdr->e_phnum; h++ )
182 {
183 phdr = (Elf_Phdr *)(image + ehdr->e_phoff + (h*ehdr->e_phentsize));
184 if ( !is_loadable_phdr(phdr) )
185 continue;
187 for ( done = 0; done < phdr->p_filesz; done += chunksz )
188 {
189 pa = (phdr->p_paddr + done) - dsi->v_start;
190 va = xc_map_foreign_range(
191 xch, dom, PAGE_SIZE, PROT_WRITE, parray[pa>>PAGE_SHIFT]);
192 chunksz = phdr->p_filesz - done;
193 if ( chunksz > (PAGE_SIZE - (pa & (PAGE_SIZE-1))) )
194 chunksz = PAGE_SIZE - (pa & (PAGE_SIZE-1));
195 memcpy(va + (pa & (PAGE_SIZE-1)),
196 image + phdr->p_offset + done, chunksz);
197 munmap(va, PAGE_SIZE);
198 }
200 for ( ; done < phdr->p_memsz; done += chunksz )
201 {
202 pa = (phdr->p_paddr + done) - dsi->v_start;
203 va = xc_map_foreign_range(
204 xch, dom, PAGE_SIZE, PROT_WRITE, parray[pa>>PAGE_SHIFT]);
205 chunksz = phdr->p_memsz - done;
206 if ( chunksz > (PAGE_SIZE - (pa & (PAGE_SIZE-1))) )
207 chunksz = PAGE_SIZE - (pa & (PAGE_SIZE-1));
208 memset(va + (pa & (PAGE_SIZE-1)), 0, chunksz);
209 munmap(va, PAGE_SIZE);
210 }
211 }
213 loadelfsymtab(image, xch, dom, parray, dsi);
215 return 0;
216 }
218 #define ELFROUND (ELFSIZE / 8)
220 static int
221 loadelfsymtab(
222 char *image, int xch, u32 dom, unsigned long *parray,
223 struct domain_setup_info *dsi)
224 {
225 Elf_Ehdr *ehdr = (Elf_Ehdr *)image, *sym_ehdr;
226 Elf_Shdr *shdr;
227 unsigned long maxva, symva;
228 char *p;
229 int h, i;
231 if ( !dsi->load_symtab )
232 return 0;
234 p = malloc(sizeof(int) + sizeof(Elf_Ehdr) +
235 ehdr->e_shnum * sizeof(Elf_Shdr));
236 if (p == NULL)
237 return 0;
239 maxva = (dsi->v_kernend + ELFROUND - 1) & ~(ELFROUND - 1);
240 symva = maxva;
241 maxva += sizeof(int);
242 dsi->symtab_addr = maxva;
243 dsi->symtab_len = 0;
244 maxva += sizeof(Elf_Ehdr) + ehdr->e_shnum * sizeof(Elf_Shdr);
245 maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1);
247 shdr = (Elf_Shdr *)(p + sizeof(int) + sizeof(Elf_Ehdr));
248 memcpy(shdr, image + ehdr->e_shoff, ehdr->e_shnum * sizeof(Elf_Shdr));
250 for ( h = 0; h < ehdr->e_shnum; h++ )
251 {
252 if ( shdr[h].sh_type == SHT_STRTAB )
253 {
254 /* Look for a strtab @i linked to symtab @h. */
255 for ( i = 0; i < ehdr->e_shnum; i++ )
256 if ( (shdr[i].sh_type == SHT_SYMTAB) &&
257 (shdr[i].sh_link == h) )
258 break;
259 /* Skip symtab @h if we found no corresponding strtab @i. */
260 if ( i == ehdr->e_shnum )
261 {
262 shdr[h].sh_offset = 0;
263 continue;
264 }
265 }
267 if ( (shdr[h].sh_type == SHT_STRTAB) ||
268 (shdr[h].sh_type == SHT_SYMTAB) )
269 {
270 if ( parray != NULL )
271 xc_map_memcpy(maxva, image + shdr[h].sh_offset, shdr[h].sh_size,
272 xch, dom, parray, dsi->v_start);
274 /* Mangled to be based on ELF header location. */
275 shdr[h].sh_offset = maxva - dsi->symtab_addr;
277 dsi->symtab_len += shdr[h].sh_size;
278 maxva += shdr[h].sh_size;
279 maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1);
280 }
282 shdr[h].sh_name = 0; /* Name is NULL. */
283 }
285 if ( dsi->symtab_len == 0 )
286 {
287 dsi->symtab_addr = 0;
288 goto out;
289 }
291 if ( parray != NULL )
292 {
293 *(int *)p = maxva - dsi->symtab_addr;
294 sym_ehdr = (Elf_Ehdr *)(p + sizeof(int));
295 memcpy(sym_ehdr, ehdr, sizeof(Elf_Ehdr));
296 sym_ehdr->e_phoff = 0;
297 sym_ehdr->e_shoff = sizeof(Elf_Ehdr);
298 sym_ehdr->e_phentsize = 0;
299 sym_ehdr->e_phnum = 0;
300 sym_ehdr->e_shstrndx = SHN_UNDEF;
302 /* Copy total length, crafted ELF header and section header table */
303 xc_map_memcpy(symva, p, sizeof(int) + sizeof(Elf_Ehdr) +
304 ehdr->e_shnum * sizeof(Elf_Shdr), xch, dom, parray,
305 dsi->v_start);
306 }
308 dsi->symtab_len = maxva - dsi->symtab_addr;
309 dsi->v_end = round_pgup(maxva);
311 out:
312 free(p);
314 return 0;
315 }
317 /*
318 * Local variables:
319 * mode: C
320 * c-set-style: "BSD"
321 * c-basic-offset: 4
322 * tab-width: 4
323 * indent-tabs-mode: nil
324 * End:
325 */