ia64/xen-unstable

view tools/libxc/xc_load_elf.c @ 6432:b54144915ae6

merge?
author cl349@firebug.cl.cam.ac.uk
date Thu Aug 25 16:26:30 2005 +0000 (2005-08-25)
parents 3428d58a85e1 fdfd511768a3
children 0610add7c3fe
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 }